blob: d9a877ce0712f972a7c832e737ad5d130975a2d5 [file] [log] [blame]
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07001/*
2 * QTI Secure Execution Environment Communicator (QSEECOM) driver
3 *
Zhen Kong87dcf0e2019-01-04 12:34:50 -08004 * Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07005 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 and
8 * only version 2 as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
15
16#define pr_fmt(fmt) "QSEECOM: %s: " fmt, __func__
17
18#include <linux/kernel.h>
19#include <linux/slab.h>
20#include <linux/module.h>
21#include <linux/fs.h>
22#include <linux/platform_device.h>
23#include <linux/debugfs.h>
24#include <linux/cdev.h>
25#include <linux/uaccess.h>
26#include <linux/sched.h>
27#include <linux/list.h>
28#include <linux/mutex.h>
29#include <linux/io.h>
30#include <linux/msm_ion.h>
31#include <linux/types.h>
32#include <linux/clk.h>
33#include <linux/qseecom.h>
34#include <linux/elf.h>
35#include <linux/firmware.h>
36#include <linux/freezer.h>
37#include <linux/scatterlist.h>
38#include <linux/regulator/consumer.h>
39#include <linux/dma-mapping.h>
40#include <soc/qcom/subsystem_restart.h>
41#include <soc/qcom/scm.h>
42#include <soc/qcom/socinfo.h>
43#include <linux/msm-bus.h>
44#include <linux/msm-bus-board.h>
45#include <soc/qcom/qseecomi.h>
46#include <asm/cacheflush.h>
47#include "qseecom_kernel.h"
48#include <crypto/ice.h>
49#include <linux/delay.h>
50
51#include <linux/compat.h>
52#include "compat_qseecom.h"
53
54#define QSEECOM_DEV "qseecom"
55#define QSEOS_VERSION_14 0x14
56#define QSEEE_VERSION_00 0x400000
57#define QSEE_VERSION_01 0x401000
58#define QSEE_VERSION_02 0x402000
59#define QSEE_VERSION_03 0x403000
60#define QSEE_VERSION_04 0x404000
61#define QSEE_VERSION_05 0x405000
62#define QSEE_VERSION_20 0x800000
63#define QSEE_VERSION_40 0x1000000 /* TZ.BF.4.0 */
64
65#define QSEE_CE_CLK_100MHZ 100000000
66#define CE_CLK_DIV 1000000
67
Mohamed Sunfeer105a07b2018-08-29 13:52:40 +053068#define QSEECOM_MAX_SG_ENTRY 4096
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -070069#define QSEECOM_SG_ENTRY_MSG_BUF_SZ_64BIT \
70 (QSEECOM_MAX_SG_ENTRY * SG_ENTRY_SZ_64BIT)
71
72#define QSEECOM_INVALID_KEY_ID 0xff
73
74/* Save partition image hash for authentication check */
75#define SCM_SAVE_PARTITION_HASH_ID 0x01
76
77/* Check if enterprise security is activate */
78#define SCM_IS_ACTIVATED_ID 0x02
79
80/* Encrypt/Decrypt Data Integrity Partition (DIP) for MDTP */
81#define SCM_MDTP_CIPHER_DIP 0x01
82
83/* Maximum Allowed Size (128K) of Data Integrity Partition (DIP) for MDTP */
84#define MAX_DIP 0x20000
85
86#define RPMB_SERVICE 0x2000
87#define SSD_SERVICE 0x3000
88
89#define QSEECOM_SEND_CMD_CRYPTO_TIMEOUT 2000
90#define QSEECOM_LOAD_APP_CRYPTO_TIMEOUT 2000
91#define TWO 2
92#define QSEECOM_UFS_ICE_CE_NUM 10
93#define QSEECOM_SDCC_ICE_CE_NUM 20
94#define QSEECOM_ICE_FDE_KEY_INDEX 0
95
96#define PHY_ADDR_4G (1ULL<<32)
97
98#define QSEECOM_STATE_NOT_READY 0
99#define QSEECOM_STATE_SUSPEND 1
100#define QSEECOM_STATE_READY 2
101#define QSEECOM_ICE_FDE_KEY_SIZE_MASK 2
102
103/*
104 * default ce info unit to 0 for
105 * services which
106 * support only single instance.
107 * Most of services are in this category.
108 */
109#define DEFAULT_CE_INFO_UNIT 0
110#define DEFAULT_NUM_CE_INFO_UNIT 1
111
Jiten Patela7bb1d52018-05-11 12:34:26 +0530112#define FDE_FLAG_POS 4
113#define ENABLE_KEY_WRAP_IN_KS (1 << FDE_FLAG_POS)
114
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -0700115enum qseecom_clk_definitions {
116 CLK_DFAB = 0,
117 CLK_SFPB,
118};
119
120enum qseecom_ice_key_size_type {
121 QSEECOM_ICE_FDE_KEY_SIZE_16_BYTE =
122 (0 << QSEECOM_ICE_FDE_KEY_SIZE_MASK),
123 QSEECOM_ICE_FDE_KEY_SIZE_32_BYTE =
124 (1 << QSEECOM_ICE_FDE_KEY_SIZE_MASK),
125 QSEE_ICE_FDE_KEY_SIZE_UNDEFINED =
126 (0xF << QSEECOM_ICE_FDE_KEY_SIZE_MASK),
127};
128
129enum qseecom_client_handle_type {
130 QSEECOM_CLIENT_APP = 1,
131 QSEECOM_LISTENER_SERVICE,
132 QSEECOM_SECURE_SERVICE,
133 QSEECOM_GENERIC,
134 QSEECOM_UNAVAILABLE_CLIENT_APP,
135};
136
137enum qseecom_ce_hw_instance {
138 CLK_QSEE = 0,
139 CLK_CE_DRV,
140 CLK_INVALID,
141};
142
143static struct class *driver_class;
144static dev_t qseecom_device_no;
145
146static DEFINE_MUTEX(qsee_bw_mutex);
147static DEFINE_MUTEX(app_access_lock);
148static DEFINE_MUTEX(clk_access_lock);
Zhen Kongbcdeda22018-11-16 13:50:51 -0800149static DEFINE_MUTEX(listener_access_lock);
150
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -0700151
152struct sglist_info {
153 uint32_t indexAndFlags;
154 uint32_t sizeOrCount;
155};
156
157/*
158 * The 31th bit indicates only one or multiple physical address inside
159 * the request buffer. If it is set, the index locates a single physical addr
160 * inside the request buffer, and `sizeOrCount` is the size of the memory being
161 * shared at that physical address.
162 * Otherwise, the index locates an array of {start, len} pairs (a
163 * "scatter/gather list"), and `sizeOrCount` gives the number of entries in
164 * that array.
165 *
166 * The 30th bit indicates 64 or 32bit address; when it is set, physical addr
167 * and scatter gather entry sizes are 64-bit values. Otherwise, 32-bit values.
168 *
169 * The bits [0:29] of `indexAndFlags` hold an offset into the request buffer.
170 */
171#define SGLISTINFO_SET_INDEX_FLAG(c, s, i) \
172 ((uint32_t)(((c & 1) << 31) | ((s & 1) << 30) | (i & 0x3fffffff)))
173
174#define SGLISTINFO_TABLE_SIZE (sizeof(struct sglist_info) * MAX_ION_FD)
175
176#define FEATURE_ID_WHITELIST 15 /*whitelist feature id*/
177
178#define MAKE_WHITELIST_VERSION(major, minor, patch) \
179 (((major & 0x3FF) << 22) | ((minor & 0x3FF) << 12) | (patch & 0xFFF))
180
181struct qseecom_registered_listener_list {
182 struct list_head list;
183 struct qseecom_register_listener_req svc;
184 void *user_virt_sb_base;
185 u8 *sb_virt;
186 phys_addr_t sb_phys;
187 size_t sb_length;
188 struct ion_handle *ihandle; /* Retrieve phy addr */
189 wait_queue_head_t rcv_req_wq;
Zhen Kongbcdeda22018-11-16 13:50:51 -0800190 /* rcv_req_flag: 0: ready and empty; 1: received req */
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -0700191 int rcv_req_flag;
192 int send_resp_flag;
193 bool listener_in_use;
194 /* wq for thread blocked on this listener*/
195 wait_queue_head_t listener_block_app_wq;
Zhen Kongbcdeda22018-11-16 13:50:51 -0800196 struct sglist_info sglistinfo_ptr[MAX_ION_FD];
197 uint32_t sglist_cnt;
198 int abort;
199 bool unregister_pending;
200};
201
202struct qseecom_unregister_pending_list {
203 struct list_head list;
204 struct qseecom_dev_handle *data;
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -0700205};
206
207struct qseecom_registered_app_list {
208 struct list_head list;
209 u32 app_id;
210 u32 ref_cnt;
211 char app_name[MAX_APP_NAME_SIZE];
212 u32 app_arch;
213 bool app_blocked;
Zhen Kongdea10592018-07-30 17:50:10 -0700214 u32 check_block;
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -0700215 u32 blocked_on_listener_id;
216};
217
218struct qseecom_registered_kclient_list {
219 struct list_head list;
220 struct qseecom_handle *handle;
221};
222
223struct qseecom_ce_info_use {
224 unsigned char handle[MAX_CE_INFO_HANDLE_SIZE];
225 unsigned int unit_num;
226 unsigned int num_ce_pipe_entries;
227 struct qseecom_ce_pipe_entry *ce_pipe_entry;
228 bool alloc;
229 uint32_t type;
230};
231
232struct ce_hw_usage_info {
233 uint32_t qsee_ce_hw_instance;
234 uint32_t num_fde;
235 struct qseecom_ce_info_use *fde;
236 uint32_t num_pfe;
237 struct qseecom_ce_info_use *pfe;
238};
239
240struct qseecom_clk {
241 enum qseecom_ce_hw_instance instance;
242 struct clk *ce_core_clk;
243 struct clk *ce_clk;
244 struct clk *ce_core_src_clk;
245 struct clk *ce_bus_clk;
246 uint32_t clk_access_cnt;
247};
248
249struct qseecom_control {
250 struct ion_client *ion_clnt; /* Ion client */
251 struct list_head registered_listener_list_head;
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -0700252
253 struct list_head registered_app_list_head;
254 spinlock_t registered_app_list_lock;
255
256 struct list_head registered_kclient_list_head;
257 spinlock_t registered_kclient_list_lock;
258
259 wait_queue_head_t send_resp_wq;
260 int send_resp_flag;
261
262 uint32_t qseos_version;
263 uint32_t qsee_version;
264 struct device *pdev;
265 bool whitelist_support;
266 bool commonlib_loaded;
267 bool commonlib64_loaded;
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -0700268 struct ce_hw_usage_info ce_info;
269
270 int qsee_bw_count;
271 int qsee_sfpb_bw_count;
272
273 uint32_t qsee_perf_client;
274 struct qseecom_clk qsee;
275 struct qseecom_clk ce_drv;
276
277 bool support_bus_scaling;
278 bool support_fde;
279 bool support_pfe;
280 bool fde_key_size;
281 uint32_t cumulative_mode;
282 enum qseecom_bandwidth_request_mode current_mode;
283 struct timer_list bw_scale_down_timer;
284 struct work_struct bw_inactive_req_ws;
285 struct cdev cdev;
286 bool timer_running;
287 bool no_clock_support;
288 unsigned int ce_opp_freq_hz;
289 bool appsbl_qseecom_support;
290 uint32_t qsee_reentrancy_support;
Jiten Patela7bb1d52018-05-11 12:34:26 +0530291 bool enable_key_wrap_in_ks;
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -0700292
293 uint32_t app_block_ref_cnt;
294 wait_queue_head_t app_block_wq;
295 atomic_t qseecom_state;
296 int is_apps_region_protected;
Zhen Kong2f60f492017-06-29 15:22:14 -0700297 bool smcinvoke_support;
Zhen Kongbcdeda22018-11-16 13:50:51 -0800298
299 struct list_head unregister_lsnr_pending_list_head;
300 wait_queue_head_t register_lsnr_pending_wq;
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -0700301};
302
303struct qseecom_sec_buf_fd_info {
304 bool is_sec_buf_fd;
305 size_t size;
306 void *vbase;
307 dma_addr_t pbase;
308};
309
310struct qseecom_param_memref {
311 uint32_t buffer;
312 uint32_t size;
313};
314
315struct qseecom_client_handle {
316 u32 app_id;
317 u8 *sb_virt;
318 phys_addr_t sb_phys;
319 unsigned long user_virt_sb_base;
320 size_t sb_length;
321 struct ion_handle *ihandle; /* Retrieve phy addr */
322 char app_name[MAX_APP_NAME_SIZE];
323 u32 app_arch;
324 struct qseecom_sec_buf_fd_info sec_buf_fd[MAX_ION_FD];
325};
326
327struct qseecom_listener_handle {
328 u32 id;
Zhen Kongbcdeda22018-11-16 13:50:51 -0800329 bool unregister_pending;
Zhen Kong87dcf0e2019-01-04 12:34:50 -0800330 bool release_called;
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -0700331};
332
333static struct qseecom_control qseecom;
334
335struct qseecom_dev_handle {
336 enum qseecom_client_handle_type type;
337 union {
338 struct qseecom_client_handle client;
339 struct qseecom_listener_handle listener;
340 };
341 bool released;
342 int abort;
343 wait_queue_head_t abort_wq;
344 atomic_t ioctl_count;
345 bool perf_enabled;
346 bool fast_load_enabled;
347 enum qseecom_bandwidth_request_mode mode;
348 struct sglist_info sglistinfo_ptr[MAX_ION_FD];
349 uint32_t sglist_cnt;
350 bool use_legacy_cmd;
351};
352
353struct qseecom_key_id_usage_desc {
354 uint8_t desc[QSEECOM_KEY_ID_SIZE];
355};
356
357struct qseecom_crypto_info {
358 unsigned int unit_num;
359 unsigned int ce;
360 unsigned int pipe_pair;
361};
362
363static struct qseecom_key_id_usage_desc key_id_array[] = {
364 {
365 .desc = "Undefined Usage Index",
366 },
367
368 {
369 .desc = "Full Disk Encryption",
370 },
371
372 {
373 .desc = "Per File Encryption",
374 },
375
376 {
377 .desc = "UFS ICE Full Disk Encryption",
378 },
379
380 {
381 .desc = "SDCC ICE Full Disk Encryption",
382 },
383};
384
385/* Function proto types */
386static int qsee_vote_for_clock(struct qseecom_dev_handle *, int32_t);
387static void qsee_disable_clock_vote(struct qseecom_dev_handle *, int32_t);
388static int __qseecom_enable_clk(enum qseecom_ce_hw_instance ce);
389static void __qseecom_disable_clk(enum qseecom_ce_hw_instance ce);
390static int __qseecom_init_clk(enum qseecom_ce_hw_instance ce);
391static int qseecom_load_commonlib_image(struct qseecom_dev_handle *data,
392 char *cmnlib_name);
393static int qseecom_enable_ice_setup(int usage);
394static int qseecom_disable_ice_setup(int usage);
395static void __qseecom_reentrancy_check_if_no_app_blocked(uint32_t smc_id);
396static int qseecom_get_ce_info(struct qseecom_dev_handle *data,
397 void __user *argp);
398static int qseecom_free_ce_info(struct qseecom_dev_handle *data,
399 void __user *argp);
400static int qseecom_query_ce_info(struct qseecom_dev_handle *data,
401 void __user *argp);
402
403static int get_qseecom_keymaster_status(char *str)
404{
405 get_option(&str, &qseecom.is_apps_region_protected);
406 return 1;
407}
408__setup("androidboot.keymaster=", get_qseecom_keymaster_status);
409
410static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
411 const void *req_buf, void *resp_buf)
412{
413 int ret = 0;
414 uint32_t smc_id = 0;
415 uint32_t qseos_cmd_id = 0;
416 struct scm_desc desc = {0};
417 struct qseecom_command_scm_resp *scm_resp = NULL;
418
419 if (!req_buf || !resp_buf) {
420 pr_err("Invalid buffer pointer\n");
421 return -EINVAL;
422 }
423 qseos_cmd_id = *(uint32_t *)req_buf;
424 scm_resp = (struct qseecom_command_scm_resp *)resp_buf;
425
426 switch (svc_id) {
427 case 6: {
428 if (tz_cmd_id == 3) {
429 smc_id = TZ_INFO_GET_FEATURE_VERSION_ID;
430 desc.arginfo = TZ_INFO_GET_FEATURE_VERSION_ID_PARAM_ID;
431 desc.args[0] = *(uint32_t *)req_buf;
432 } else {
433 pr_err("Unsupported svc_id %d, tz_cmd_id %d\n",
434 svc_id, tz_cmd_id);
435 return -EINVAL;
436 }
437 ret = scm_call2(smc_id, &desc);
438 break;
439 }
440 case SCM_SVC_ES: {
441 switch (tz_cmd_id) {
442 case SCM_SAVE_PARTITION_HASH_ID: {
443 u32 tzbuflen = PAGE_ALIGN(SHA256_DIGEST_LENGTH);
444 struct qseecom_save_partition_hash_req *p_hash_req =
445 (struct qseecom_save_partition_hash_req *)
446 req_buf;
447 char *tzbuf = kzalloc(tzbuflen, GFP_KERNEL);
448
449 if (!tzbuf)
450 return -ENOMEM;
451 memset(tzbuf, 0, tzbuflen);
452 memcpy(tzbuf, p_hash_req->digest,
453 SHA256_DIGEST_LENGTH);
454 dmac_flush_range(tzbuf, tzbuf + tzbuflen);
455 smc_id = TZ_ES_SAVE_PARTITION_HASH_ID;
456 desc.arginfo = TZ_ES_SAVE_PARTITION_HASH_ID_PARAM_ID;
457 desc.args[0] = p_hash_req->partition_id;
458 desc.args[1] = virt_to_phys(tzbuf);
459 desc.args[2] = SHA256_DIGEST_LENGTH;
460 ret = scm_call2(smc_id, &desc);
461 kzfree(tzbuf);
462 break;
463 }
464 default: {
465 pr_err("tz_cmd_id %d is not supported by scm_call2\n",
466 tz_cmd_id);
467 ret = -EINVAL;
468 break;
469 }
470 } /* end of switch (tz_cmd_id) */
471 break;
472 } /* end of case SCM_SVC_ES */
473 case SCM_SVC_TZSCHEDULER: {
474 switch (qseos_cmd_id) {
475 case QSEOS_APP_START_COMMAND: {
476 struct qseecom_load_app_ireq *req;
477 struct qseecom_load_app_64bit_ireq *req_64bit;
478
479 smc_id = TZ_OS_APP_START_ID;
480 desc.arginfo = TZ_OS_APP_START_ID_PARAM_ID;
481 if (qseecom.qsee_version < QSEE_VERSION_40) {
482 req = (struct qseecom_load_app_ireq *)req_buf;
483 desc.args[0] = req->mdt_len;
484 desc.args[1] = req->img_len;
485 desc.args[2] = req->phy_addr;
486 } else {
487 req_64bit =
488 (struct qseecom_load_app_64bit_ireq *)
489 req_buf;
490 desc.args[0] = req_64bit->mdt_len;
491 desc.args[1] = req_64bit->img_len;
492 desc.args[2] = req_64bit->phy_addr;
493 }
494 __qseecom_reentrancy_check_if_no_app_blocked(smc_id);
495 ret = scm_call2(smc_id, &desc);
496 break;
497 }
498 case QSEOS_APP_SHUTDOWN_COMMAND: {
499 struct qseecom_unload_app_ireq *req;
500
501 req = (struct qseecom_unload_app_ireq *)req_buf;
502 smc_id = TZ_OS_APP_SHUTDOWN_ID;
503 desc.arginfo = TZ_OS_APP_SHUTDOWN_ID_PARAM_ID;
504 desc.args[0] = req->app_id;
505 ret = scm_call2(smc_id, &desc);
506 break;
507 }
508 case QSEOS_APP_LOOKUP_COMMAND: {
509 struct qseecom_check_app_ireq *req;
510 u32 tzbuflen = PAGE_ALIGN(sizeof(req->app_name));
511 char *tzbuf = kzalloc(tzbuflen, GFP_KERNEL);
512
513 if (!tzbuf)
514 return -ENOMEM;
515 req = (struct qseecom_check_app_ireq *)req_buf;
516 pr_debug("Lookup app_name = %s\n", req->app_name);
517 strlcpy(tzbuf, req->app_name, sizeof(req->app_name));
518 dmac_flush_range(tzbuf, tzbuf + tzbuflen);
519 smc_id = TZ_OS_APP_LOOKUP_ID;
520 desc.arginfo = TZ_OS_APP_LOOKUP_ID_PARAM_ID;
521 desc.args[0] = virt_to_phys(tzbuf);
522 desc.args[1] = strlen(req->app_name);
523 __qseecom_reentrancy_check_if_no_app_blocked(smc_id);
524 ret = scm_call2(smc_id, &desc);
525 kzfree(tzbuf);
526 break;
527 }
528 case QSEOS_APP_REGION_NOTIFICATION: {
529 struct qsee_apps_region_info_ireq *req;
530 struct qsee_apps_region_info_64bit_ireq *req_64bit;
531
532 smc_id = TZ_OS_APP_REGION_NOTIFICATION_ID;
533 desc.arginfo =
534 TZ_OS_APP_REGION_NOTIFICATION_ID_PARAM_ID;
535 if (qseecom.qsee_version < QSEE_VERSION_40) {
536 req = (struct qsee_apps_region_info_ireq *)
537 req_buf;
538 desc.args[0] = req->addr;
539 desc.args[1] = req->size;
540 } else {
541 req_64bit =
542 (struct qsee_apps_region_info_64bit_ireq *)
543 req_buf;
544 desc.args[0] = req_64bit->addr;
545 desc.args[1] = req_64bit->size;
546 }
547 __qseecom_reentrancy_check_if_no_app_blocked(smc_id);
548 ret = scm_call2(smc_id, &desc);
549 break;
550 }
551 case QSEOS_LOAD_SERV_IMAGE_COMMAND: {
552 struct qseecom_load_lib_image_ireq *req;
553 struct qseecom_load_lib_image_64bit_ireq *req_64bit;
554
555 smc_id = TZ_OS_LOAD_SERVICES_IMAGE_ID;
556 desc.arginfo = TZ_OS_LOAD_SERVICES_IMAGE_ID_PARAM_ID;
557 if (qseecom.qsee_version < QSEE_VERSION_40) {
558 req = (struct qseecom_load_lib_image_ireq *)
559 req_buf;
560 desc.args[0] = req->mdt_len;
561 desc.args[1] = req->img_len;
562 desc.args[2] = req->phy_addr;
563 } else {
564 req_64bit =
565 (struct qseecom_load_lib_image_64bit_ireq *)
566 req_buf;
567 desc.args[0] = req_64bit->mdt_len;
568 desc.args[1] = req_64bit->img_len;
569 desc.args[2] = req_64bit->phy_addr;
570 }
571 __qseecom_reentrancy_check_if_no_app_blocked(smc_id);
572 ret = scm_call2(smc_id, &desc);
573 break;
574 }
575 case QSEOS_UNLOAD_SERV_IMAGE_COMMAND: {
576 smc_id = TZ_OS_UNLOAD_SERVICES_IMAGE_ID;
577 desc.arginfo = TZ_OS_UNLOAD_SERVICES_IMAGE_ID_PARAM_ID;
578 __qseecom_reentrancy_check_if_no_app_blocked(smc_id);
579 ret = scm_call2(smc_id, &desc);
580 break;
581 }
582 case QSEOS_REGISTER_LISTENER: {
583 struct qseecom_register_listener_ireq *req;
584 struct qseecom_register_listener_64bit_ireq *req_64bit;
585
586 desc.arginfo =
587 TZ_OS_REGISTER_LISTENER_ID_PARAM_ID;
588 if (qseecom.qsee_version < QSEE_VERSION_40) {
589 req = (struct qseecom_register_listener_ireq *)
590 req_buf;
591 desc.args[0] = req->listener_id;
592 desc.args[1] = req->sb_ptr;
593 desc.args[2] = req->sb_len;
594 } else {
595 req_64bit =
596 (struct qseecom_register_listener_64bit_ireq *)
597 req_buf;
598 desc.args[0] = req_64bit->listener_id;
599 desc.args[1] = req_64bit->sb_ptr;
600 desc.args[2] = req_64bit->sb_len;
601 }
Zhen Kong2f60f492017-06-29 15:22:14 -0700602 qseecom.smcinvoke_support = true;
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -0700603 smc_id = TZ_OS_REGISTER_LISTENER_SMCINVOKE_ID;
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -0700604 ret = scm_call2(smc_id, &desc);
Zhen Kongbcdeda22018-11-16 13:50:51 -0800605 if (ret && ret != -EBUSY) {
Zhen Kong2f60f492017-06-29 15:22:14 -0700606 qseecom.smcinvoke_support = false;
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -0700607 smc_id = TZ_OS_REGISTER_LISTENER_ID;
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -0700608 ret = scm_call2(smc_id, &desc);
609 }
610 break;
611 }
612 case QSEOS_DEREGISTER_LISTENER: {
613 struct qseecom_unregister_listener_ireq *req;
614
615 req = (struct qseecom_unregister_listener_ireq *)
616 req_buf;
617 smc_id = TZ_OS_DEREGISTER_LISTENER_ID;
618 desc.arginfo = TZ_OS_DEREGISTER_LISTENER_ID_PARAM_ID;
619 desc.args[0] = req->listener_id;
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -0700620 ret = scm_call2(smc_id, &desc);
621 break;
622 }
623 case QSEOS_LISTENER_DATA_RSP_COMMAND: {
624 struct qseecom_client_listener_data_irsp *req;
625
626 req = (struct qseecom_client_listener_data_irsp *)
627 req_buf;
628 smc_id = TZ_OS_LISTENER_RESPONSE_HANDLER_ID;
629 desc.arginfo =
630 TZ_OS_LISTENER_RESPONSE_HANDLER_ID_PARAM_ID;
631 desc.args[0] = req->listener_id;
632 desc.args[1] = req->status;
633 ret = scm_call2(smc_id, &desc);
634 break;
635 }
636 case QSEOS_LISTENER_DATA_RSP_COMMAND_WHITELIST: {
637 struct qseecom_client_listener_data_irsp *req;
638 struct qseecom_client_listener_data_64bit_irsp *req_64;
639
640 smc_id =
641 TZ_OS_LISTENER_RESPONSE_HANDLER_WITH_WHITELIST_ID;
642 desc.arginfo =
643 TZ_OS_LISTENER_RESPONSE_HANDLER_WITH_WHITELIST_PARAM_ID;
644 if (qseecom.qsee_version < QSEE_VERSION_40) {
645 req =
646 (struct qseecom_client_listener_data_irsp *)
647 req_buf;
648 desc.args[0] = req->listener_id;
649 desc.args[1] = req->status;
650 desc.args[2] = req->sglistinfo_ptr;
651 desc.args[3] = req->sglistinfo_len;
652 } else {
653 req_64 =
654 (struct qseecom_client_listener_data_64bit_irsp *)
655 req_buf;
656 desc.args[0] = req_64->listener_id;
657 desc.args[1] = req_64->status;
658 desc.args[2] = req_64->sglistinfo_ptr;
659 desc.args[3] = req_64->sglistinfo_len;
660 }
661 ret = scm_call2(smc_id, &desc);
662 break;
663 }
664 case QSEOS_LOAD_EXTERNAL_ELF_COMMAND: {
665 struct qseecom_load_app_ireq *req;
666 struct qseecom_load_app_64bit_ireq *req_64bit;
667
668 smc_id = TZ_OS_LOAD_EXTERNAL_IMAGE_ID;
669 desc.arginfo = TZ_OS_LOAD_SERVICES_IMAGE_ID_PARAM_ID;
670 if (qseecom.qsee_version < QSEE_VERSION_40) {
671 req = (struct qseecom_load_app_ireq *)req_buf;
672 desc.args[0] = req->mdt_len;
673 desc.args[1] = req->img_len;
674 desc.args[2] = req->phy_addr;
675 } else {
676 req_64bit =
677 (struct qseecom_load_app_64bit_ireq *)req_buf;
678 desc.args[0] = req_64bit->mdt_len;
679 desc.args[1] = req_64bit->img_len;
680 desc.args[2] = req_64bit->phy_addr;
681 }
682 __qseecom_reentrancy_check_if_no_app_blocked(smc_id);
683 ret = scm_call2(smc_id, &desc);
684 break;
685 }
686 case QSEOS_UNLOAD_EXTERNAL_ELF_COMMAND: {
687 smc_id = TZ_OS_UNLOAD_EXTERNAL_IMAGE_ID;
688 desc.arginfo = TZ_OS_UNLOAD_SERVICES_IMAGE_ID_PARAM_ID;
689 __qseecom_reentrancy_check_if_no_app_blocked(smc_id);
690 ret = scm_call2(smc_id, &desc);
691 break;
692 }
693
694 case QSEOS_CLIENT_SEND_DATA_COMMAND: {
695 struct qseecom_client_send_data_ireq *req;
696 struct qseecom_client_send_data_64bit_ireq *req_64bit;
697
698 smc_id = TZ_APP_QSAPP_SEND_DATA_ID;
699 desc.arginfo = TZ_APP_QSAPP_SEND_DATA_ID_PARAM_ID;
700 if (qseecom.qsee_version < QSEE_VERSION_40) {
701 req = (struct qseecom_client_send_data_ireq *)
702 req_buf;
703 desc.args[0] = req->app_id;
704 desc.args[1] = req->req_ptr;
705 desc.args[2] = req->req_len;
706 desc.args[3] = req->rsp_ptr;
707 desc.args[4] = req->rsp_len;
708 } else {
709 req_64bit =
710 (struct qseecom_client_send_data_64bit_ireq *)
711 req_buf;
712 desc.args[0] = req_64bit->app_id;
713 desc.args[1] = req_64bit->req_ptr;
714 desc.args[2] = req_64bit->req_len;
715 desc.args[3] = req_64bit->rsp_ptr;
716 desc.args[4] = req_64bit->rsp_len;
717 }
718 ret = scm_call2(smc_id, &desc);
719 break;
720 }
721 case QSEOS_CLIENT_SEND_DATA_COMMAND_WHITELIST: {
722 struct qseecom_client_send_data_ireq *req;
723 struct qseecom_client_send_data_64bit_ireq *req_64bit;
724
725 smc_id = TZ_APP_QSAPP_SEND_DATA_WITH_WHITELIST_ID;
726 desc.arginfo =
727 TZ_APP_QSAPP_SEND_DATA_WITH_WHITELIST_ID_PARAM_ID;
728 if (qseecom.qsee_version < QSEE_VERSION_40) {
729 req = (struct qseecom_client_send_data_ireq *)
730 req_buf;
731 desc.args[0] = req->app_id;
732 desc.args[1] = req->req_ptr;
733 desc.args[2] = req->req_len;
734 desc.args[3] = req->rsp_ptr;
735 desc.args[4] = req->rsp_len;
736 desc.args[5] = req->sglistinfo_ptr;
737 desc.args[6] = req->sglistinfo_len;
738 } else {
739 req_64bit =
740 (struct qseecom_client_send_data_64bit_ireq *)
741 req_buf;
742 desc.args[0] = req_64bit->app_id;
743 desc.args[1] = req_64bit->req_ptr;
744 desc.args[2] = req_64bit->req_len;
745 desc.args[3] = req_64bit->rsp_ptr;
746 desc.args[4] = req_64bit->rsp_len;
747 desc.args[5] = req_64bit->sglistinfo_ptr;
748 desc.args[6] = req_64bit->sglistinfo_len;
749 }
750 ret = scm_call2(smc_id, &desc);
751 break;
752 }
753 case QSEOS_RPMB_PROVISION_KEY_COMMAND: {
754 struct qseecom_client_send_service_ireq *req;
755
756 req = (struct qseecom_client_send_service_ireq *)
757 req_buf;
758 smc_id = TZ_OS_RPMB_PROVISION_KEY_ID;
759 desc.arginfo = TZ_OS_RPMB_PROVISION_KEY_ID_PARAM_ID;
760 desc.args[0] = req->key_type;
761 __qseecom_reentrancy_check_if_no_app_blocked(smc_id);
762 ret = scm_call2(smc_id, &desc);
763 break;
764 }
765 case QSEOS_RPMB_ERASE_COMMAND: {
766 smc_id = TZ_OS_RPMB_ERASE_ID;
767 desc.arginfo = TZ_OS_RPMB_ERASE_ID_PARAM_ID;
768 __qseecom_reentrancy_check_if_no_app_blocked(smc_id);
769 ret = scm_call2(smc_id, &desc);
770 break;
771 }
772 case QSEOS_RPMB_CHECK_PROV_STATUS_COMMAND: {
773 smc_id = TZ_OS_RPMB_CHECK_PROV_STATUS_ID;
774 desc.arginfo = TZ_OS_RPMB_CHECK_PROV_STATUS_ID_PARAM_ID;
775 __qseecom_reentrancy_check_if_no_app_blocked(smc_id);
776 ret = scm_call2(smc_id, &desc);
777 break;
778 }
779 case QSEOS_GENERATE_KEY: {
780 u32 tzbuflen = PAGE_ALIGN(sizeof
781 (struct qseecom_key_generate_ireq) -
782 sizeof(uint32_t));
783 char *tzbuf = kzalloc(tzbuflen, GFP_KERNEL);
784
785 if (!tzbuf)
786 return -ENOMEM;
787 memset(tzbuf, 0, tzbuflen);
788 memcpy(tzbuf, req_buf + sizeof(uint32_t),
789 (sizeof(struct qseecom_key_generate_ireq) -
790 sizeof(uint32_t)));
791 dmac_flush_range(tzbuf, tzbuf + tzbuflen);
792 smc_id = TZ_OS_KS_GEN_KEY_ID;
793 desc.arginfo = TZ_OS_KS_GEN_KEY_ID_PARAM_ID;
794 desc.args[0] = virt_to_phys(tzbuf);
795 desc.args[1] = tzbuflen;
796 __qseecom_reentrancy_check_if_no_app_blocked(smc_id);
797 ret = scm_call2(smc_id, &desc);
798 kzfree(tzbuf);
799 break;
800 }
801 case QSEOS_DELETE_KEY: {
802 u32 tzbuflen = PAGE_ALIGN(sizeof
803 (struct qseecom_key_delete_ireq) -
804 sizeof(uint32_t));
805 char *tzbuf = kzalloc(tzbuflen, GFP_KERNEL);
806
807 if (!tzbuf)
808 return -ENOMEM;
809 memset(tzbuf, 0, tzbuflen);
810 memcpy(tzbuf, req_buf + sizeof(uint32_t),
811 (sizeof(struct qseecom_key_delete_ireq) -
812 sizeof(uint32_t)));
813 dmac_flush_range(tzbuf, tzbuf + tzbuflen);
814 smc_id = TZ_OS_KS_DEL_KEY_ID;
815 desc.arginfo = TZ_OS_KS_DEL_KEY_ID_PARAM_ID;
816 desc.args[0] = virt_to_phys(tzbuf);
817 desc.args[1] = tzbuflen;
818 __qseecom_reentrancy_check_if_no_app_blocked(smc_id);
819 ret = scm_call2(smc_id, &desc);
820 kzfree(tzbuf);
821 break;
822 }
823 case QSEOS_SET_KEY: {
824 u32 tzbuflen = PAGE_ALIGN(sizeof
825 (struct qseecom_key_select_ireq) -
826 sizeof(uint32_t));
827 char *tzbuf = kzalloc(tzbuflen, GFP_KERNEL);
828
829 if (!tzbuf)
830 return -ENOMEM;
831 memset(tzbuf, 0, tzbuflen);
832 memcpy(tzbuf, req_buf + sizeof(uint32_t),
833 (sizeof(struct qseecom_key_select_ireq) -
834 sizeof(uint32_t)));
835 dmac_flush_range(tzbuf, tzbuf + tzbuflen);
836 smc_id = TZ_OS_KS_SET_PIPE_KEY_ID;
837 desc.arginfo = TZ_OS_KS_SET_PIPE_KEY_ID_PARAM_ID;
838 desc.args[0] = virt_to_phys(tzbuf);
839 desc.args[1] = tzbuflen;
840 __qseecom_reentrancy_check_if_no_app_blocked(smc_id);
841 ret = scm_call2(smc_id, &desc);
842 kzfree(tzbuf);
843 break;
844 }
845 case QSEOS_UPDATE_KEY_USERINFO: {
846 u32 tzbuflen = PAGE_ALIGN(sizeof
847 (struct qseecom_key_userinfo_update_ireq) -
848 sizeof(uint32_t));
849 char *tzbuf = kzalloc(tzbuflen, GFP_KERNEL);
850
851 if (!tzbuf)
852 return -ENOMEM;
853 memset(tzbuf, 0, tzbuflen);
854 memcpy(tzbuf, req_buf + sizeof(uint32_t), (sizeof
855 (struct qseecom_key_userinfo_update_ireq) -
856 sizeof(uint32_t)));
857 dmac_flush_range(tzbuf, tzbuf + tzbuflen);
858 smc_id = TZ_OS_KS_UPDATE_KEY_ID;
859 desc.arginfo = TZ_OS_KS_UPDATE_KEY_ID_PARAM_ID;
860 desc.args[0] = virt_to_phys(tzbuf);
861 desc.args[1] = tzbuflen;
862 __qseecom_reentrancy_check_if_no_app_blocked(smc_id);
863 ret = scm_call2(smc_id, &desc);
864 kzfree(tzbuf);
865 break;
866 }
867 case QSEOS_TEE_OPEN_SESSION: {
868 struct qseecom_qteec_ireq *req;
869 struct qseecom_qteec_64bit_ireq *req_64bit;
870
871 smc_id = TZ_APP_GPAPP_OPEN_SESSION_ID;
872 desc.arginfo = TZ_APP_GPAPP_OPEN_SESSION_ID_PARAM_ID;
873 if (qseecom.qsee_version < QSEE_VERSION_40) {
874 req = (struct qseecom_qteec_ireq *)req_buf;
875 desc.args[0] = req->app_id;
876 desc.args[1] = req->req_ptr;
877 desc.args[2] = req->req_len;
878 desc.args[3] = req->resp_ptr;
879 desc.args[4] = req->resp_len;
880 } else {
881 req_64bit = (struct qseecom_qteec_64bit_ireq *)
882 req_buf;
883 desc.args[0] = req_64bit->app_id;
884 desc.args[1] = req_64bit->req_ptr;
885 desc.args[2] = req_64bit->req_len;
886 desc.args[3] = req_64bit->resp_ptr;
887 desc.args[4] = req_64bit->resp_len;
888 }
889 ret = scm_call2(smc_id, &desc);
890 break;
891 }
892 case QSEOS_TEE_OPEN_SESSION_WHITELIST: {
893 struct qseecom_qteec_ireq *req;
894 struct qseecom_qteec_64bit_ireq *req_64bit;
895
896 smc_id = TZ_APP_GPAPP_OPEN_SESSION_WITH_WHITELIST_ID;
897 desc.arginfo =
898 TZ_APP_GPAPP_OPEN_SESSION_WITH_WHITELIST_ID_PARAM_ID;
899 if (qseecom.qsee_version < QSEE_VERSION_40) {
900 req = (struct qseecom_qteec_ireq *)req_buf;
901 desc.args[0] = req->app_id;
902 desc.args[1] = req->req_ptr;
903 desc.args[2] = req->req_len;
904 desc.args[3] = req->resp_ptr;
905 desc.args[4] = req->resp_len;
906 desc.args[5] = req->sglistinfo_ptr;
907 desc.args[6] = req->sglistinfo_len;
908 } else {
909 req_64bit = (struct qseecom_qteec_64bit_ireq *)
910 req_buf;
911 desc.args[0] = req_64bit->app_id;
912 desc.args[1] = req_64bit->req_ptr;
913 desc.args[2] = req_64bit->req_len;
914 desc.args[3] = req_64bit->resp_ptr;
915 desc.args[4] = req_64bit->resp_len;
916 desc.args[5] = req_64bit->sglistinfo_ptr;
917 desc.args[6] = req_64bit->sglistinfo_len;
918 }
919 ret = scm_call2(smc_id, &desc);
920 break;
921 }
922 case QSEOS_TEE_INVOKE_COMMAND: {
923 struct qseecom_qteec_ireq *req;
924 struct qseecom_qteec_64bit_ireq *req_64bit;
925
926 smc_id = TZ_APP_GPAPP_INVOKE_COMMAND_ID;
927 desc.arginfo = TZ_APP_GPAPP_INVOKE_COMMAND_ID_PARAM_ID;
928 if (qseecom.qsee_version < QSEE_VERSION_40) {
929 req = (struct qseecom_qteec_ireq *)req_buf;
930 desc.args[0] = req->app_id;
931 desc.args[1] = req->req_ptr;
932 desc.args[2] = req->req_len;
933 desc.args[3] = req->resp_ptr;
934 desc.args[4] = req->resp_len;
935 } else {
936 req_64bit = (struct qseecom_qteec_64bit_ireq *)
937 req_buf;
938 desc.args[0] = req_64bit->app_id;
939 desc.args[1] = req_64bit->req_ptr;
940 desc.args[2] = req_64bit->req_len;
941 desc.args[3] = req_64bit->resp_ptr;
942 desc.args[4] = req_64bit->resp_len;
943 }
944 ret = scm_call2(smc_id, &desc);
945 break;
946 }
947 case QSEOS_TEE_INVOKE_COMMAND_WHITELIST: {
948 struct qseecom_qteec_ireq *req;
949 struct qseecom_qteec_64bit_ireq *req_64bit;
950
951 smc_id = TZ_APP_GPAPP_INVOKE_COMMAND_WITH_WHITELIST_ID;
952 desc.arginfo =
953 TZ_APP_GPAPP_INVOKE_COMMAND_WITH_WHITELIST_ID_PARAM_ID;
954 if (qseecom.qsee_version < QSEE_VERSION_40) {
955 req = (struct qseecom_qteec_ireq *)req_buf;
956 desc.args[0] = req->app_id;
957 desc.args[1] = req->req_ptr;
958 desc.args[2] = req->req_len;
959 desc.args[3] = req->resp_ptr;
960 desc.args[4] = req->resp_len;
961 desc.args[5] = req->sglistinfo_ptr;
962 desc.args[6] = req->sglistinfo_len;
963 } else {
964 req_64bit = (struct qseecom_qteec_64bit_ireq *)
965 req_buf;
966 desc.args[0] = req_64bit->app_id;
967 desc.args[1] = req_64bit->req_ptr;
968 desc.args[2] = req_64bit->req_len;
969 desc.args[3] = req_64bit->resp_ptr;
970 desc.args[4] = req_64bit->resp_len;
971 desc.args[5] = req_64bit->sglistinfo_ptr;
972 desc.args[6] = req_64bit->sglistinfo_len;
973 }
974 ret = scm_call2(smc_id, &desc);
975 break;
976 }
977 case QSEOS_TEE_CLOSE_SESSION: {
978 struct qseecom_qteec_ireq *req;
979 struct qseecom_qteec_64bit_ireq *req_64bit;
980
981 smc_id = TZ_APP_GPAPP_CLOSE_SESSION_ID;
982 desc.arginfo = TZ_APP_GPAPP_CLOSE_SESSION_ID_PARAM_ID;
983 if (qseecom.qsee_version < QSEE_VERSION_40) {
984 req = (struct qseecom_qteec_ireq *)req_buf;
985 desc.args[0] = req->app_id;
986 desc.args[1] = req->req_ptr;
987 desc.args[2] = req->req_len;
988 desc.args[3] = req->resp_ptr;
989 desc.args[4] = req->resp_len;
990 } else {
991 req_64bit = (struct qseecom_qteec_64bit_ireq *)
992 req_buf;
993 desc.args[0] = req_64bit->app_id;
994 desc.args[1] = req_64bit->req_ptr;
995 desc.args[2] = req_64bit->req_len;
996 desc.args[3] = req_64bit->resp_ptr;
997 desc.args[4] = req_64bit->resp_len;
998 }
999 ret = scm_call2(smc_id, &desc);
1000 break;
1001 }
1002 case QSEOS_TEE_REQUEST_CANCELLATION: {
1003 struct qseecom_qteec_ireq *req;
1004 struct qseecom_qteec_64bit_ireq *req_64bit;
1005
1006 smc_id = TZ_APP_GPAPP_REQUEST_CANCELLATION_ID;
1007 desc.arginfo =
1008 TZ_APP_GPAPP_REQUEST_CANCELLATION_ID_PARAM_ID;
1009 if (qseecom.qsee_version < QSEE_VERSION_40) {
1010 req = (struct qseecom_qteec_ireq *)req_buf;
1011 desc.args[0] = req->app_id;
1012 desc.args[1] = req->req_ptr;
1013 desc.args[2] = req->req_len;
1014 desc.args[3] = req->resp_ptr;
1015 desc.args[4] = req->resp_len;
1016 } else {
1017 req_64bit = (struct qseecom_qteec_64bit_ireq *)
1018 req_buf;
1019 desc.args[0] = req_64bit->app_id;
1020 desc.args[1] = req_64bit->req_ptr;
1021 desc.args[2] = req_64bit->req_len;
1022 desc.args[3] = req_64bit->resp_ptr;
1023 desc.args[4] = req_64bit->resp_len;
1024 }
1025 ret = scm_call2(smc_id, &desc);
1026 break;
1027 }
1028 case QSEOS_CONTINUE_BLOCKED_REQ_COMMAND: {
1029 struct qseecom_continue_blocked_request_ireq *req =
1030 (struct qseecom_continue_blocked_request_ireq *)
1031 req_buf;
Zhen Kong2f60f492017-06-29 15:22:14 -07001032 if (qseecom.smcinvoke_support)
1033 smc_id =
1034 TZ_OS_CONTINUE_BLOCKED_REQUEST_SMCINVOKE_ID;
1035 else
1036 smc_id = TZ_OS_CONTINUE_BLOCKED_REQUEST_ID;
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07001037 desc.arginfo =
1038 TZ_OS_CONTINUE_BLOCKED_REQUEST_ID_PARAM_ID;
Zhen Kong2f60f492017-06-29 15:22:14 -07001039 desc.args[0] = req->app_or_session_id;
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07001040 ret = scm_call2(smc_id, &desc);
1041 break;
1042 }
1043 default: {
1044 pr_err("qseos_cmd_id %d is not supported by armv8 scm_call2.\n",
1045 qseos_cmd_id);
1046 ret = -EINVAL;
1047 break;
1048 }
1049 } /*end of switch (qsee_cmd_id) */
1050 break;
1051 } /*end of case SCM_SVC_TZSCHEDULER*/
1052 default: {
1053 pr_err("svc_id 0x%x is not supported by armv8 scm_call2.\n",
1054 svc_id);
1055 ret = -EINVAL;
1056 break;
1057 }
1058 } /*end of switch svc_id */
1059 scm_resp->result = desc.ret[0];
1060 scm_resp->resp_type = desc.ret[1];
1061 scm_resp->data = desc.ret[2];
1062 pr_debug("svc_id = 0x%x, tz_cmd_id = 0x%x, qseos_cmd_id = 0x%x, smc_id = 0x%x, param_id = 0x%x\n",
1063 svc_id, tz_cmd_id, qseos_cmd_id, smc_id, desc.arginfo);
1064 pr_debug("scm_resp->result = 0x%x, scm_resp->resp_type = 0x%x, scm_resp->data = 0x%x\n",
1065 scm_resp->result, scm_resp->resp_type, scm_resp->data);
1066 return ret;
1067}
1068
1069
1070static int qseecom_scm_call(u32 svc_id, u32 tz_cmd_id, const void *cmd_buf,
1071 size_t cmd_len, void *resp_buf, size_t resp_len)
1072{
1073 if (!is_scm_armv8())
1074 return scm_call(svc_id, tz_cmd_id, cmd_buf, cmd_len,
1075 resp_buf, resp_len);
1076 else
1077 return qseecom_scm_call2(svc_id, tz_cmd_id, cmd_buf, resp_buf);
1078}
1079
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07001080static struct qseecom_registered_listener_list *__qseecom_find_svc(
1081 int32_t listener_id)
1082{
1083 struct qseecom_registered_listener_list *entry = NULL;
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07001084
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07001085 list_for_each_entry(entry,
1086 &qseecom.registered_listener_list_head, list) {
1087 if (entry->svc.listener_id == listener_id)
1088 break;
1089 }
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07001090 if ((entry != NULL) && (entry->svc.listener_id != listener_id)) {
Zhen Kongbcdeda22018-11-16 13:50:51 -08001091 pr_debug("Service id: %u is not found\n", listener_id);
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07001092 return NULL;
1093 }
1094
1095 return entry;
1096}
1097
1098static int __qseecom_set_sb_memory(struct qseecom_registered_listener_list *svc,
1099 struct qseecom_dev_handle *handle,
1100 struct qseecom_register_listener_req *listener)
1101{
1102 int ret = 0;
1103 struct qseecom_register_listener_ireq req;
1104 struct qseecom_register_listener_64bit_ireq req_64bit;
1105 struct qseecom_command_scm_resp resp;
1106 ion_phys_addr_t pa;
1107 void *cmd_buf = NULL;
1108 size_t cmd_len;
1109
1110 /* Get the handle of the shared fd */
AnilKumar Chimata04d60cf2017-04-09 11:43:10 -07001111 svc->ihandle = ion_import_dma_buf_fd(qseecom.ion_clnt,
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07001112 listener->ifd_data_fd);
1113 if (IS_ERR_OR_NULL(svc->ihandle)) {
1114 pr_err("Ion client could not retrieve the handle\n");
1115 return -ENOMEM;
1116 }
1117
1118 /* Get the physical address of the ION BUF */
1119 ret = ion_phys(qseecom.ion_clnt, svc->ihandle, &pa, &svc->sb_length);
1120 if (ret) {
1121 pr_err("Cannot get phys_addr for the Ion Client, ret = %d\n",
1122 ret);
1123 return ret;
1124 }
1125 /* Populate the structure for sending scm call to load image */
1126 svc->sb_virt = (char *) ion_map_kernel(qseecom.ion_clnt, svc->ihandle);
1127 if (IS_ERR_OR_NULL(svc->sb_virt)) {
1128 pr_err("ION memory mapping for listener shared buffer failed\n");
1129 return -ENOMEM;
1130 }
1131 svc->sb_phys = (phys_addr_t)pa;
1132
1133 if (qseecom.qsee_version < QSEE_VERSION_40) {
1134 req.qsee_cmd_id = QSEOS_REGISTER_LISTENER;
1135 req.listener_id = svc->svc.listener_id;
1136 req.sb_len = svc->sb_length;
1137 req.sb_ptr = (uint32_t)svc->sb_phys;
1138 cmd_buf = (void *)&req;
1139 cmd_len = sizeof(struct qseecom_register_listener_ireq);
1140 } else {
1141 req_64bit.qsee_cmd_id = QSEOS_REGISTER_LISTENER;
1142 req_64bit.listener_id = svc->svc.listener_id;
1143 req_64bit.sb_len = svc->sb_length;
1144 req_64bit.sb_ptr = (uint64_t)svc->sb_phys;
1145 cmd_buf = (void *)&req_64bit;
1146 cmd_len = sizeof(struct qseecom_register_listener_64bit_ireq);
1147 }
1148
1149 resp.result = QSEOS_RESULT_INCOMPLETE;
1150
1151 ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, cmd_buf, cmd_len,
1152 &resp, sizeof(resp));
1153 if (ret) {
1154 pr_err("qseecom_scm_call failed with err: %d\n", ret);
1155 return -EINVAL;
1156 }
1157
1158 if (resp.result != QSEOS_RESULT_SUCCESS) {
1159 pr_err("Error SB registration req: resp.result = %d\n",
1160 resp.result);
1161 return -EPERM;
1162 }
1163 return 0;
1164}
1165
1166static int qseecom_register_listener(struct qseecom_dev_handle *data,
1167 void __user *argp)
1168{
1169 int ret = 0;
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07001170 struct qseecom_register_listener_req rcvd_lstnr;
1171 struct qseecom_registered_listener_list *new_entry;
Zhen Kongbcdeda22018-11-16 13:50:51 -08001172 struct qseecom_registered_listener_list *ptr_svc;
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07001173
1174 ret = copy_from_user(&rcvd_lstnr, argp, sizeof(rcvd_lstnr));
1175 if (ret) {
1176 pr_err("copy_from_user failed\n");
1177 return ret;
1178 }
1179 if (!access_ok(VERIFY_WRITE, (void __user *)rcvd_lstnr.virt_sb_base,
1180 rcvd_lstnr.sb_size))
1181 return -EFAULT;
1182
Zhen Kong3c674612018-09-06 22:51:27 -07001183 data->listener.id = rcvd_lstnr.listener_id;
Zhen Kongbcdeda22018-11-16 13:50:51 -08001184
1185 ptr_svc = __qseecom_find_svc(rcvd_lstnr.listener_id);
1186 if (ptr_svc) {
1187 if (ptr_svc->unregister_pending == false) {
1188 pr_err("Service %d is not unique\n",
Zhen Kong3c674612018-09-06 22:51:27 -07001189 rcvd_lstnr.listener_id);
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07001190 data->released = true;
1191 return -EBUSY;
Zhen Kongbcdeda22018-11-16 13:50:51 -08001192 } else {
1193 /*wait until listener is unregistered*/
1194 pr_debug("register %d has to wait\n",
1195 rcvd_lstnr.listener_id);
1196 mutex_unlock(&listener_access_lock);
1197 ret = wait_event_freezable(
1198 qseecom.register_lsnr_pending_wq,
1199 list_empty(
1200 &qseecom.unregister_lsnr_pending_list_head));
1201 if (ret) {
1202 pr_err("interrupted register_pending_wq %d\n",
1203 rcvd_lstnr.listener_id);
1204 mutex_lock(&listener_access_lock);
1205 return -ERESTARTSYS;
1206 }
1207 mutex_lock(&listener_access_lock);
1208 }
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07001209 }
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07001210 new_entry = kzalloc(sizeof(*new_entry), GFP_KERNEL);
1211 if (!new_entry)
1212 return -ENOMEM;
1213 memcpy(&new_entry->svc, &rcvd_lstnr, sizeof(rcvd_lstnr));
Zhen Kongbcdeda22018-11-16 13:50:51 -08001214 new_entry->rcv_req_flag = 0;
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07001215
1216 new_entry->svc.listener_id = rcvd_lstnr.listener_id;
1217 new_entry->sb_length = rcvd_lstnr.sb_size;
1218 new_entry->user_virt_sb_base = rcvd_lstnr.virt_sb_base;
1219 if (__qseecom_set_sb_memory(new_entry, data, &rcvd_lstnr)) {
Zhen Kong3c674612018-09-06 22:51:27 -07001220 pr_err("qseecom_set_sb_memory failed for listener %d, size %d\n",
1221 rcvd_lstnr.listener_id, rcvd_lstnr.sb_size);
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07001222 kzfree(new_entry);
1223 return -ENOMEM;
1224 }
1225
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07001226 init_waitqueue_head(&new_entry->rcv_req_wq);
1227 init_waitqueue_head(&new_entry->listener_block_app_wq);
1228 new_entry->send_resp_flag = 0;
1229 new_entry->listener_in_use = false;
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07001230 list_add_tail(&new_entry->list, &qseecom.registered_listener_list_head);
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07001231
Zhen Kong3c674612018-09-06 22:51:27 -07001232 pr_warn("Service %d is registered\n", rcvd_lstnr.listener_id);
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07001233 return ret;
1234}
1235
Zhen Kongbcdeda22018-11-16 13:50:51 -08001236static int __qseecom_unregister_listener(struct qseecom_dev_handle *data,
1237 struct qseecom_registered_listener_list *ptr_svc)
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07001238{
1239 int ret = 0;
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07001240 struct qseecom_register_listener_ireq req;
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07001241 struct qseecom_command_scm_resp resp;
1242 struct ion_handle *ihandle = NULL; /* Retrieve phy addr */
1243
1244 req.qsee_cmd_id = QSEOS_DEREGISTER_LISTENER;
1245 req.listener_id = data->listener.id;
1246 resp.result = QSEOS_RESULT_INCOMPLETE;
1247
1248 ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
1249 sizeof(req), &resp, sizeof(resp));
1250 if (ret) {
1251 pr_err("scm_call() failed with err: %d (lstnr id=%d)\n",
1252 ret, data->listener.id);
Zhen Kongbcdeda22018-11-16 13:50:51 -08001253 if (ret == -EBUSY)
1254 return ret;
Zhen Kong3c674612018-09-06 22:51:27 -07001255 goto exit;
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07001256 }
1257
1258 if (resp.result != QSEOS_RESULT_SUCCESS) {
1259 pr_err("Failed resp.result=%d,(lstnr id=%d)\n",
1260 resp.result, data->listener.id);
Zhen Kong3c674612018-09-06 22:51:27 -07001261 ret = -EPERM;
1262 goto exit;
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07001263 }
1264
1265 data->abort = 1;
Zhen Kong3c674612018-09-06 22:51:27 -07001266 wake_up_all(&ptr_svc->rcv_req_wq);
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07001267
1268 while (atomic_read(&data->ioctl_count) > 1) {
1269 if (wait_event_freezable(data->abort_wq,
1270 atomic_read(&data->ioctl_count) <= 1)) {
1271 pr_err("Interrupted from abort\n");
1272 ret = -ERESTARTSYS;
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07001273 }
1274 }
1275
Zhen Kong3c674612018-09-06 22:51:27 -07001276exit:
1277 if (ptr_svc->sb_virt) {
1278 ihandle = ptr_svc->ihandle;
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07001279 if (!IS_ERR_OR_NULL(ihandle)) {
1280 ion_unmap_kernel(qseecom.ion_clnt, ihandle);
1281 ion_free(qseecom.ion_clnt, ihandle);
1282 }
1283 }
Zhen Kong3c674612018-09-06 22:51:27 -07001284 list_del(&ptr_svc->list);
1285 kzfree(ptr_svc);
1286
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07001287 data->released = true;
Zhen Kong3c674612018-09-06 22:51:27 -07001288 pr_warn("Service %d is unregistered\n", data->listener.id);
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07001289 return ret;
1290}
1291
Zhen Kongbcdeda22018-11-16 13:50:51 -08001292static int qseecom_unregister_listener(struct qseecom_dev_handle *data)
1293{
1294 struct qseecom_registered_listener_list *ptr_svc = NULL;
1295 struct qseecom_unregister_pending_list *entry = NULL;
1296
1297 ptr_svc = __qseecom_find_svc(data->listener.id);
1298 if (!ptr_svc) {
1299 pr_err("Unregiser invalid listener ID %d\n", data->listener.id);
1300 return -ENODATA;
1301 }
1302 /* stop CA thread waiting for listener response */
1303 ptr_svc->abort = 1;
1304 wake_up_interruptible_all(&qseecom.send_resp_wq);
1305
1306 /* return directly if pending*/
1307 if (ptr_svc->unregister_pending)
1308 return 0;
1309
1310 /*add unregistration into pending list*/
1311 entry = kzalloc(sizeof(*entry), GFP_KERNEL);
1312 if (!entry)
1313 return -ENOMEM;
1314 entry->data = data;
1315 list_add_tail(&entry->list,
1316 &qseecom.unregister_lsnr_pending_list_head);
1317 ptr_svc->unregister_pending = true;
1318 pr_debug("unregister %d pending\n", data->listener.id);
1319 return 0;
1320}
1321
1322static void __qseecom_processing_pending_lsnr_unregister(void)
1323{
1324 struct qseecom_unregister_pending_list *entry = NULL;
1325 struct qseecom_registered_listener_list *ptr_svc = NULL;
1326 struct list_head *pos;
1327 int ret = 0;
1328
1329 mutex_lock(&listener_access_lock);
1330 while (!list_empty(&qseecom.unregister_lsnr_pending_list_head)) {
1331 pos = qseecom.unregister_lsnr_pending_list_head.next;
1332 entry = list_entry(pos,
1333 struct qseecom_unregister_pending_list, list);
1334 if (entry && entry->data) {
1335 pr_debug("process pending unregister %d\n",
1336 entry->data->listener.id);
Zhen Kong87dcf0e2019-01-04 12:34:50 -08001337 /* don't process if qseecom_release is not called*/
1338 if (!entry->data->listener.release_called)
1339 break;
Zhen Kongbcdeda22018-11-16 13:50:51 -08001340 ptr_svc = __qseecom_find_svc(
1341 entry->data->listener.id);
1342 if (ptr_svc) {
1343 ret = __qseecom_unregister_listener(
1344 entry->data, ptr_svc);
1345 if (ret == -EBUSY) {
1346 pr_debug("unregister %d pending again\n",
1347 entry->data->listener.id);
1348 mutex_unlock(&listener_access_lock);
1349 return;
1350 }
1351 } else
1352 pr_err("invalid listener %d\n",
1353 entry->data->listener.id);
1354 kzfree(entry->data);
1355 }
1356 list_del(pos);
1357 kzfree(entry);
1358 }
1359 mutex_unlock(&listener_access_lock);
1360 wake_up_interruptible(&qseecom.register_lsnr_pending_wq);
1361}
1362
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07001363static int __qseecom_set_msm_bus_request(uint32_t mode)
1364{
1365 int ret = 0;
1366 struct qseecom_clk *qclk;
1367
1368 qclk = &qseecom.qsee;
1369 if (qclk->ce_core_src_clk != NULL) {
1370 if (mode == INACTIVE) {
1371 __qseecom_disable_clk(CLK_QSEE);
1372 } else {
1373 ret = __qseecom_enable_clk(CLK_QSEE);
1374 if (ret)
1375 pr_err("CLK enabling failed (%d) MODE (%d)\n",
1376 ret, mode);
1377 }
1378 }
1379
1380 if ((!ret) && (qseecom.current_mode != mode)) {
1381 ret = msm_bus_scale_client_update_request(
1382 qseecom.qsee_perf_client, mode);
1383 if (ret) {
1384 pr_err("Bandwidth req failed(%d) MODE (%d)\n",
1385 ret, mode);
1386 if (qclk->ce_core_src_clk != NULL) {
1387 if (mode == INACTIVE) {
1388 ret = __qseecom_enable_clk(CLK_QSEE);
1389 if (ret)
1390 pr_err("CLK enable failed\n");
1391 } else
1392 __qseecom_disable_clk(CLK_QSEE);
1393 }
1394 }
1395 qseecom.current_mode = mode;
1396 }
1397 return ret;
1398}
1399
1400static void qseecom_bw_inactive_req_work(struct work_struct *work)
1401{
1402 mutex_lock(&app_access_lock);
1403 mutex_lock(&qsee_bw_mutex);
1404 if (qseecom.timer_running)
1405 __qseecom_set_msm_bus_request(INACTIVE);
1406 pr_debug("current_mode = %d, cumulative_mode = %d\n",
1407 qseecom.current_mode, qseecom.cumulative_mode);
1408 qseecom.timer_running = false;
1409 mutex_unlock(&qsee_bw_mutex);
1410 mutex_unlock(&app_access_lock);
1411}
1412
1413static void qseecom_scale_bus_bandwidth_timer_callback(unsigned long data)
1414{
1415 schedule_work(&qseecom.bw_inactive_req_ws);
1416}
1417
1418static int __qseecom_decrease_clk_ref_count(enum qseecom_ce_hw_instance ce)
1419{
1420 struct qseecom_clk *qclk;
1421 int ret = 0;
1422
1423 mutex_lock(&clk_access_lock);
1424 if (ce == CLK_QSEE)
1425 qclk = &qseecom.qsee;
1426 else
1427 qclk = &qseecom.ce_drv;
1428
1429 if (qclk->clk_access_cnt > 2) {
1430 pr_err("Invalid clock ref count %d\n", qclk->clk_access_cnt);
1431 ret = -EINVAL;
1432 goto err_dec_ref_cnt;
1433 }
1434 if (qclk->clk_access_cnt == 2)
1435 qclk->clk_access_cnt--;
1436
1437err_dec_ref_cnt:
1438 mutex_unlock(&clk_access_lock);
1439 return ret;
1440}
1441
1442
1443static int qseecom_scale_bus_bandwidth_timer(uint32_t mode)
1444{
1445 int32_t ret = 0;
1446 int32_t request_mode = INACTIVE;
1447
1448 mutex_lock(&qsee_bw_mutex);
1449 if (mode == 0) {
1450 if (qseecom.cumulative_mode > MEDIUM)
1451 request_mode = HIGH;
1452 else
1453 request_mode = qseecom.cumulative_mode;
1454 } else {
1455 request_mode = mode;
1456 }
1457
1458 ret = __qseecom_set_msm_bus_request(request_mode);
1459 if (ret) {
1460 pr_err("set msm bus request failed (%d),request_mode (%d)\n",
1461 ret, request_mode);
1462 goto err_scale_timer;
1463 }
1464
1465 if (qseecom.timer_running) {
1466 ret = __qseecom_decrease_clk_ref_count(CLK_QSEE);
1467 if (ret) {
1468 pr_err("Failed to decrease clk ref count.\n");
1469 goto err_scale_timer;
1470 }
1471 del_timer_sync(&(qseecom.bw_scale_down_timer));
1472 qseecom.timer_running = false;
1473 }
1474err_scale_timer:
1475 mutex_unlock(&qsee_bw_mutex);
1476 return ret;
1477}
1478
1479
1480static int qseecom_unregister_bus_bandwidth_needs(
1481 struct qseecom_dev_handle *data)
1482{
1483 int32_t ret = 0;
1484
1485 qseecom.cumulative_mode -= data->mode;
1486 data->mode = INACTIVE;
1487
1488 return ret;
1489}
1490
1491static int __qseecom_register_bus_bandwidth_needs(
1492 struct qseecom_dev_handle *data, uint32_t request_mode)
1493{
1494 int32_t ret = 0;
1495
1496 if (data->mode == INACTIVE) {
1497 qseecom.cumulative_mode += request_mode;
1498 data->mode = request_mode;
1499 } else {
1500 if (data->mode != request_mode) {
1501 qseecom.cumulative_mode -= data->mode;
1502 qseecom.cumulative_mode += request_mode;
1503 data->mode = request_mode;
1504 }
1505 }
1506 return ret;
1507}
1508
1509static int qseecom_perf_enable(struct qseecom_dev_handle *data)
1510{
1511 int ret = 0;
1512
1513 ret = qsee_vote_for_clock(data, CLK_DFAB);
1514 if (ret) {
1515 pr_err("Failed to vote for DFAB clock with err %d\n", ret);
1516 goto perf_enable_exit;
1517 }
1518 ret = qsee_vote_for_clock(data, CLK_SFPB);
1519 if (ret) {
1520 qsee_disable_clock_vote(data, CLK_DFAB);
1521 pr_err("Failed to vote for SFPB clock with err %d\n", ret);
1522 goto perf_enable_exit;
1523 }
1524
1525perf_enable_exit:
1526 return ret;
1527}
1528
1529static int qseecom_scale_bus_bandwidth(struct qseecom_dev_handle *data,
1530 void __user *argp)
1531{
1532 int32_t ret = 0;
1533 int32_t req_mode;
1534
1535 if (qseecom.no_clock_support)
1536 return 0;
1537
1538 ret = copy_from_user(&req_mode, argp, sizeof(req_mode));
1539 if (ret) {
1540 pr_err("copy_from_user failed\n");
1541 return ret;
1542 }
1543 if (req_mode > HIGH) {
1544 pr_err("Invalid bandwidth mode (%d)\n", req_mode);
1545 return -EINVAL;
1546 }
1547
1548 /*
1549 * Register bus bandwidth needs if bus scaling feature is enabled;
1550 * otherwise, qseecom enable/disable clocks for the client directly.
1551 */
1552 if (qseecom.support_bus_scaling) {
1553 mutex_lock(&qsee_bw_mutex);
1554 ret = __qseecom_register_bus_bandwidth_needs(data, req_mode);
1555 mutex_unlock(&qsee_bw_mutex);
1556 } else {
1557 pr_debug("Bus scaling feature is NOT enabled\n");
1558 pr_debug("request bandwidth mode %d for the client\n",
1559 req_mode);
1560 if (req_mode != INACTIVE) {
1561 ret = qseecom_perf_enable(data);
1562 if (ret)
1563 pr_err("Failed to vote for clock with err %d\n",
1564 ret);
1565 } else {
1566 qsee_disable_clock_vote(data, CLK_DFAB);
1567 qsee_disable_clock_vote(data, CLK_SFPB);
1568 }
1569 }
1570 return ret;
1571}
1572
1573static void __qseecom_add_bw_scale_down_timer(uint32_t duration)
1574{
1575 if (qseecom.no_clock_support)
1576 return;
1577
1578 mutex_lock(&qsee_bw_mutex);
1579 qseecom.bw_scale_down_timer.expires = jiffies +
1580 msecs_to_jiffies(duration);
1581 mod_timer(&(qseecom.bw_scale_down_timer),
1582 qseecom.bw_scale_down_timer.expires);
1583 qseecom.timer_running = true;
1584 mutex_unlock(&qsee_bw_mutex);
1585}
1586
1587static void __qseecom_disable_clk_scale_down(struct qseecom_dev_handle *data)
1588{
1589 if (!qseecom.support_bus_scaling)
1590 qsee_disable_clock_vote(data, CLK_SFPB);
1591 else
1592 __qseecom_add_bw_scale_down_timer(
1593 QSEECOM_LOAD_APP_CRYPTO_TIMEOUT);
1594}
1595
1596static int __qseecom_enable_clk_scale_up(struct qseecom_dev_handle *data)
1597{
1598 int ret = 0;
1599
1600 if (qseecom.support_bus_scaling) {
1601 ret = qseecom_scale_bus_bandwidth_timer(MEDIUM);
1602 if (ret)
1603 pr_err("Failed to set bw MEDIUM.\n");
1604 } else {
1605 ret = qsee_vote_for_clock(data, CLK_SFPB);
1606 if (ret)
1607 pr_err("Fail vote for clk SFPB ret %d\n", ret);
1608 }
1609 return ret;
1610}
1611
1612static int qseecom_set_client_mem_param(struct qseecom_dev_handle *data,
1613 void __user *argp)
1614{
1615 ion_phys_addr_t pa;
1616 int32_t ret;
1617 struct qseecom_set_sb_mem_param_req req;
1618 size_t len;
1619
1620 /* Copy the relevant information needed for loading the image */
1621 if (copy_from_user(&req, (void __user *)argp, sizeof(req)))
1622 return -EFAULT;
1623
1624 if ((req.ifd_data_fd <= 0) || (req.virt_sb_base == NULL) ||
1625 (req.sb_len == 0)) {
1626 pr_err("Inavlid input(s)ion_fd(%d), sb_len(%d), vaddr(0x%pK)\n",
1627 req.ifd_data_fd, req.sb_len, req.virt_sb_base);
1628 return -EFAULT;
1629 }
1630 if (!access_ok(VERIFY_WRITE, (void __user *)req.virt_sb_base,
1631 req.sb_len))
1632 return -EFAULT;
1633
1634 /* Get the handle of the shared fd */
AnilKumar Chimata04d60cf2017-04-09 11:43:10 -07001635 data->client.ihandle = ion_import_dma_buf_fd(qseecom.ion_clnt,
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07001636 req.ifd_data_fd);
1637 if (IS_ERR_OR_NULL(data->client.ihandle)) {
1638 pr_err("Ion client could not retrieve the handle\n");
1639 return -ENOMEM;
1640 }
1641 /* Get the physical address of the ION BUF */
1642 ret = ion_phys(qseecom.ion_clnt, data->client.ihandle, &pa, &len);
1643 if (ret) {
1644
1645 pr_err("Cannot get phys_addr for the Ion Client, ret = %d\n",
1646 ret);
1647 return ret;
1648 }
1649
1650 if (len < req.sb_len) {
1651 pr_err("Requested length (0x%x) is > allocated (%zu)\n",
1652 req.sb_len, len);
1653 return -EINVAL;
1654 }
1655 /* Populate the structure for sending scm call to load image */
1656 data->client.sb_virt = (char *) ion_map_kernel(qseecom.ion_clnt,
1657 data->client.ihandle);
1658 if (IS_ERR_OR_NULL(data->client.sb_virt)) {
1659 pr_err("ION memory mapping for client shared buf failed\n");
1660 return -ENOMEM;
1661 }
1662 data->client.sb_phys = (phys_addr_t)pa;
1663 data->client.sb_length = req.sb_len;
1664 data->client.user_virt_sb_base = (uintptr_t)req.virt_sb_base;
1665 return 0;
1666}
1667
Zhen Kong26e62742018-05-04 17:19:06 -07001668static int __qseecom_listener_has_sent_rsp(struct qseecom_dev_handle *data,
1669 struct qseecom_registered_listener_list *ptr_svc)
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07001670{
1671 int ret;
1672
1673 ret = (qseecom.send_resp_flag != 0);
Zhen Kong26e62742018-05-04 17:19:06 -07001674 return ret || data->abort || ptr_svc->abort;
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07001675}
1676
1677static int __qseecom_reentrancy_listener_has_sent_rsp(
1678 struct qseecom_dev_handle *data,
1679 struct qseecom_registered_listener_list *ptr_svc)
1680{
1681 int ret;
1682
1683 ret = (ptr_svc->send_resp_flag != 0);
Zhen Kong26e62742018-05-04 17:19:06 -07001684 return ret || data->abort || ptr_svc->abort;
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07001685}
1686
1687static void __qseecom_clean_listener_sglistinfo(
1688 struct qseecom_registered_listener_list *ptr_svc)
1689{
1690 if (ptr_svc->sglist_cnt) {
1691 memset(ptr_svc->sglistinfo_ptr, 0,
1692 SGLISTINFO_TABLE_SIZE);
1693 ptr_svc->sglist_cnt = 0;
1694 }
1695}
1696
1697static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data,
1698 struct qseecom_command_scm_resp *resp)
1699{
1700 int ret = 0;
1701 int rc = 0;
1702 uint32_t lstnr;
Zhen Kong7d500032018-08-06 16:58:31 -07001703 struct qseecom_client_listener_data_irsp send_data_rsp = {0};
1704 struct qseecom_client_listener_data_64bit_irsp send_data_rsp_64bit
1705 = {0};
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07001706 struct qseecom_registered_listener_list *ptr_svc = NULL;
1707 sigset_t new_sigset;
1708 sigset_t old_sigset;
1709 uint32_t status;
1710 void *cmd_buf = NULL;
1711 size_t cmd_len;
1712 struct sglist_info *table = NULL;
1713
Zhen Kongbcdeda22018-11-16 13:50:51 -08001714 qseecom.app_block_ref_cnt++;
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07001715 while (resp->result == QSEOS_RESULT_INCOMPLETE) {
1716 lstnr = resp->data;
1717 /*
1718 * Wake up blocking lsitener service with the lstnr id
1719 */
Zhen Kongbcdeda22018-11-16 13:50:51 -08001720 mutex_lock(&listener_access_lock);
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07001721 list_for_each_entry(ptr_svc,
1722 &qseecom.registered_listener_list_head, list) {
1723 if (ptr_svc->svc.listener_id == lstnr) {
1724 ptr_svc->listener_in_use = true;
1725 ptr_svc->rcv_req_flag = 1;
1726 wake_up_interruptible(&ptr_svc->rcv_req_wq);
1727 break;
1728 }
1729 }
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07001730
1731 if (ptr_svc == NULL) {
1732 pr_err("Listener Svc %d does not exist\n", lstnr);
Zhen Kong26e62742018-05-04 17:19:06 -07001733 rc = -EINVAL;
1734 status = QSEOS_RESULT_FAILURE;
1735 goto err_resp;
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07001736 }
1737
1738 if (!ptr_svc->ihandle) {
1739 pr_err("Client handle is not initialized\n");
Zhen Kong26e62742018-05-04 17:19:06 -07001740 rc = -EINVAL;
1741 status = QSEOS_RESULT_FAILURE;
1742 goto err_resp;
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07001743 }
1744
1745 if (ptr_svc->svc.listener_id != lstnr) {
Zhen Kong26e62742018-05-04 17:19:06 -07001746 pr_err("Service %d does not exist\n",
1747 lstnr);
1748 rc = -ERESTARTSYS;
1749 ptr_svc = NULL;
1750 status = QSEOS_RESULT_FAILURE;
1751 goto err_resp;
1752 }
1753
1754 if (ptr_svc->abort == 1) {
Zhen Kongbcdeda22018-11-16 13:50:51 -08001755 pr_debug("Service %d abort %d\n",
Zhen Kong26e62742018-05-04 17:19:06 -07001756 lstnr, ptr_svc->abort);
1757 rc = -ENODEV;
1758 status = QSEOS_RESULT_FAILURE;
1759 goto err_resp;
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07001760 }
Zhen Kong25731112018-09-20 13:10:03 -07001761
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07001762 pr_debug("waking up rcv_req_wq and waiting for send_resp_wq\n");
1763
1764 /* initialize the new signal mask with all signals*/
1765 sigfillset(&new_sigset);
1766 /* block all signals */
1767 sigprocmask(SIG_SETMASK, &new_sigset, &old_sigset);
1768
Zhen Kongbcdeda22018-11-16 13:50:51 -08001769 mutex_unlock(&listener_access_lock);
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07001770 do {
1771 /*
1772 * When reentrancy is not supported, check global
1773 * send_resp_flag; otherwise, check this listener's
1774 * send_resp_flag.
1775 */
1776 if (!qseecom.qsee_reentrancy_support &&
1777 !wait_event_freezable(qseecom.send_resp_wq,
Zhen Kong26e62742018-05-04 17:19:06 -07001778 __qseecom_listener_has_sent_rsp(
1779 data, ptr_svc))) {
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07001780 break;
1781 }
1782
1783 if (qseecom.qsee_reentrancy_support &&
1784 !wait_event_freezable(qseecom.send_resp_wq,
1785 __qseecom_reentrancy_listener_has_sent_rsp(
1786 data, ptr_svc))) {
1787 break;
1788 }
1789 } while (1);
Zhen Kongbcdeda22018-11-16 13:50:51 -08001790 mutex_lock(&listener_access_lock);
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07001791 /* restore signal mask */
1792 sigprocmask(SIG_SETMASK, &old_sigset, NULL);
Zhen Kong26e62742018-05-04 17:19:06 -07001793 if (data->abort || ptr_svc->abort) {
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07001794 pr_err("Abort clnt %d waiting on lstnr svc %d, ret %d",
1795 data->client.app_id, lstnr, ret);
1796 rc = -ENODEV;
1797 status = QSEOS_RESULT_FAILURE;
1798 } else {
1799 status = QSEOS_RESULT_SUCCESS;
1800 }
Zhen Kong26e62742018-05-04 17:19:06 -07001801err_resp:
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07001802 qseecom.send_resp_flag = 0;
Zhen Kong7d500032018-08-06 16:58:31 -07001803 if (ptr_svc) {
1804 ptr_svc->send_resp_flag = 0;
1805 table = ptr_svc->sglistinfo_ptr;
1806 }
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07001807 if (qseecom.qsee_version < QSEE_VERSION_40) {
1808 send_data_rsp.listener_id = lstnr;
1809 send_data_rsp.status = status;
Zhen Kong7d500032018-08-06 16:58:31 -07001810 if (table) {
1811 send_data_rsp.sglistinfo_ptr =
1812 (uint32_t)virt_to_phys(table);
1813 send_data_rsp.sglistinfo_len =
1814 SGLISTINFO_TABLE_SIZE;
1815 dmac_flush_range((void *)table,
1816 (void *)table + SGLISTINFO_TABLE_SIZE);
1817 }
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07001818 cmd_buf = (void *)&send_data_rsp;
1819 cmd_len = sizeof(send_data_rsp);
1820 } else {
1821 send_data_rsp_64bit.listener_id = lstnr;
1822 send_data_rsp_64bit.status = status;
Zhen Kong7d500032018-08-06 16:58:31 -07001823 if (table) {
1824 send_data_rsp_64bit.sglistinfo_ptr =
1825 virt_to_phys(table);
1826 send_data_rsp_64bit.sglistinfo_len =
1827 SGLISTINFO_TABLE_SIZE;
1828 dmac_flush_range((void *)table,
1829 (void *)table + SGLISTINFO_TABLE_SIZE);
1830 }
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07001831 cmd_buf = (void *)&send_data_rsp_64bit;
1832 cmd_len = sizeof(send_data_rsp_64bit);
1833 }
Zhen Kong7d500032018-08-06 16:58:31 -07001834 if (qseecom.whitelist_support == false || table == NULL)
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07001835 *(uint32_t *)cmd_buf = QSEOS_LISTENER_DATA_RSP_COMMAND;
1836 else
1837 *(uint32_t *)cmd_buf =
1838 QSEOS_LISTENER_DATA_RSP_COMMAND_WHITELIST;
Zhen Kong4b8af612018-11-03 17:01:11 -07001839 if (ptr_svc && ptr_svc->ihandle) {
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07001840 ret = msm_ion_do_cache_op(qseecom.ion_clnt,
1841 ptr_svc->ihandle,
1842 ptr_svc->sb_virt, ptr_svc->sb_length,
1843 ION_IOC_CLEAN_INV_CACHES);
1844 if (ret) {
1845 pr_err("cache operation failed %d\n", ret);
Zhen Kongbcdeda22018-11-16 13:50:51 -08001846 goto exit;
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07001847 }
1848 }
1849
1850 if ((lstnr == RPMB_SERVICE) || (lstnr == SSD_SERVICE)) {
1851 ret = __qseecom_enable_clk(CLK_QSEE);
1852 if (ret)
Zhen Kongbcdeda22018-11-16 13:50:51 -08001853 goto exit;
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07001854 }
1855
1856 ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1,
1857 cmd_buf, cmd_len, resp, sizeof(*resp));
Zhen Kong7d500032018-08-06 16:58:31 -07001858 if (ptr_svc) {
1859 ptr_svc->listener_in_use = false;
1860 __qseecom_clean_listener_sglistinfo(ptr_svc);
1861 }
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07001862 if (ret) {
1863 pr_err("scm_call() failed with err: %d (app_id = %d)\n",
1864 ret, data->client.app_id);
1865 if ((lstnr == RPMB_SERVICE) || (lstnr == SSD_SERVICE))
1866 __qseecom_disable_clk(CLK_QSEE);
Zhen Kongbcdeda22018-11-16 13:50:51 -08001867 goto exit;
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07001868 }
Zhen Kong26e62742018-05-04 17:19:06 -07001869 pr_debug("resp status %d, res= %d, app_id = %d, lstr = %d\n",
1870 status, resp->result, data->client.app_id, lstnr);
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07001871 if ((resp->result != QSEOS_RESULT_SUCCESS) &&
1872 (resp->result != QSEOS_RESULT_INCOMPLETE)) {
1873 pr_err("fail:resp res= %d,app_id = %d,lstr = %d\n",
1874 resp->result, data->client.app_id, lstnr);
1875 ret = -EINVAL;
Zhen Kongbcdeda22018-11-16 13:50:51 -08001876 goto exit;
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07001877 }
Zhen Kongbcdeda22018-11-16 13:50:51 -08001878exit:
1879 mutex_unlock(&listener_access_lock);
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07001880 if ((lstnr == RPMB_SERVICE) || (lstnr == SSD_SERVICE))
1881 __qseecom_disable_clk(CLK_QSEE);
1882
1883 }
Zhen Kongbcdeda22018-11-16 13:50:51 -08001884 qseecom.app_block_ref_cnt--;
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07001885 if (rc)
1886 return rc;
1887
1888 return ret;
1889}
1890
Zhen Konga91aaf02018-02-02 17:21:04 -08001891static int __qseecom_process_reentrancy_blocked_on_listener(
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07001892 struct qseecom_command_scm_resp *resp,
1893 struct qseecom_registered_app_list *ptr_app,
1894 struct qseecom_dev_handle *data)
1895{
1896 struct qseecom_registered_listener_list *list_ptr;
1897 int ret = 0;
1898 struct qseecom_continue_blocked_request_ireq ireq;
1899 struct qseecom_command_scm_resp continue_resp;
Zhen Konga91aaf02018-02-02 17:21:04 -08001900 unsigned int session_id;
Zhen Kong3d1d92f2018-02-02 17:21:04 -08001901 sigset_t new_sigset;
1902 sigset_t old_sigset;
Zhen Konga91aaf02018-02-02 17:21:04 -08001903 unsigned long flags;
1904 bool found_app = false;
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07001905
1906 if (!resp || !data) {
1907 pr_err("invalid resp or data pointer\n");
1908 ret = -EINVAL;
1909 goto exit;
1910 }
1911
1912 /* find app_id & img_name from list */
1913 if (!ptr_app) {
1914 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
1915 list_for_each_entry(ptr_app, &qseecom.registered_app_list_head,
1916 list) {
1917 if ((ptr_app->app_id == data->client.app_id) &&
1918 (!strcmp(ptr_app->app_name,
1919 data->client.app_name))) {
1920 found_app = true;
1921 break;
1922 }
1923 }
1924 spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
1925 flags);
1926 if (!found_app) {
1927 pr_err("app_id %d (%s) is not found\n",
1928 data->client.app_id,
1929 (char *)data->client.app_name);
1930 ret = -ENOENT;
1931 goto exit;
1932 }
1933 }
1934
Zhen Kongd8cc0052017-11-13 15:13:31 -08001935 do {
Zhen Konga91aaf02018-02-02 17:21:04 -08001936 session_id = resp->resp_type;
Zhen Kongbcdeda22018-11-16 13:50:51 -08001937 mutex_lock(&listener_access_lock);
Zhen Konga91aaf02018-02-02 17:21:04 -08001938 list_ptr = __qseecom_find_svc(resp->data);
1939 if (!list_ptr) {
1940 pr_err("Invalid listener ID %d\n", resp->data);
1941 ret = -ENODATA;
Zhen Kongbcdeda22018-11-16 13:50:51 -08001942 mutex_unlock(&listener_access_lock);
Zhen Konge7f525f2017-12-01 18:26:25 -08001943 goto exit;
1944 }
Zhen Konga91aaf02018-02-02 17:21:04 -08001945 ptr_app->blocked_on_listener_id = resp->data;
1946
1947 pr_warn("Lsntr %d in_use %d, block session(%d) app(%d)\n",
1948 resp->data, list_ptr->listener_in_use,
1949 session_id, data->client.app_id);
1950
1951 /* sleep until listener is available */
1952 sigfillset(&new_sigset);
1953 sigprocmask(SIG_SETMASK, &new_sigset, &old_sigset);
1954
1955 do {
1956 qseecom.app_block_ref_cnt++;
1957 ptr_app->app_blocked = true;
Zhen Kongbcdeda22018-11-16 13:50:51 -08001958 mutex_unlock(&listener_access_lock);
Zhen Konga91aaf02018-02-02 17:21:04 -08001959 mutex_unlock(&app_access_lock);
1960 wait_event_freezable(
1961 list_ptr->listener_block_app_wq,
1962 !list_ptr->listener_in_use);
1963 mutex_lock(&app_access_lock);
Zhen Kongbcdeda22018-11-16 13:50:51 -08001964 mutex_lock(&listener_access_lock);
Zhen Konga91aaf02018-02-02 17:21:04 -08001965 ptr_app->app_blocked = false;
1966 qseecom.app_block_ref_cnt--;
1967 } while (list_ptr->listener_in_use);
1968
1969 sigprocmask(SIG_SETMASK, &old_sigset, NULL);
1970
1971 ptr_app->blocked_on_listener_id = 0;
1972 pr_warn("Lsntr %d is available, unblock session(%d) app(%d)\n",
1973 resp->data, session_id, data->client.app_id);
1974
1975 /* notify TZ that listener is available */
1976 ireq.qsee_cmd_id = QSEOS_CONTINUE_BLOCKED_REQ_COMMAND;
1977
1978 if (qseecom.smcinvoke_support)
1979 ireq.app_or_session_id = session_id;
1980 else
1981 ireq.app_or_session_id = data->client.app_id;
1982
1983 ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1,
1984 &ireq, sizeof(ireq),
1985 &continue_resp, sizeof(continue_resp));
1986 if (ret && qseecom.smcinvoke_support) {
1987 /* retry with legacy cmd */
1988 qseecom.smcinvoke_support = false;
1989 ireq.app_or_session_id = data->client.app_id;
1990 ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1,
1991 &ireq, sizeof(ireq),
1992 &continue_resp, sizeof(continue_resp));
1993 qseecom.smcinvoke_support = true;
1994 if (ret) {
1995 pr_err("unblock app %d or session %d fail\n",
1996 data->client.app_id, session_id);
Zhen Kongbcdeda22018-11-16 13:50:51 -08001997 mutex_unlock(&listener_access_lock);
Zhen Konga91aaf02018-02-02 17:21:04 -08001998 goto exit;
1999 }
2000 }
Zhen Kongbcdeda22018-11-16 13:50:51 -08002001 mutex_unlock(&listener_access_lock);
Zhen Konga91aaf02018-02-02 17:21:04 -08002002 resp->result = continue_resp.result;
2003 resp->resp_type = continue_resp.resp_type;
2004 resp->data = continue_resp.data;
2005 pr_debug("unblock resp = %d\n", resp->result);
2006 } while (resp->result == QSEOS_RESULT_BLOCKED_ON_LISTENER);
2007
2008 if (resp->result != QSEOS_RESULT_INCOMPLETE) {
2009 pr_err("Unexpected unblock resp %d\n", resp->result);
2010 ret = -EINVAL;
Zhen Kong2f60f492017-06-29 15:22:14 -07002011 }
Zhen Kong2f60f492017-06-29 15:22:14 -07002012exit:
2013 return ret;
2014}
2015
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07002016static int __qseecom_reentrancy_process_incomplete_cmd(
2017 struct qseecom_dev_handle *data,
2018 struct qseecom_command_scm_resp *resp)
2019{
2020 int ret = 0;
2021 int rc = 0;
2022 uint32_t lstnr;
Zhen Kong7d500032018-08-06 16:58:31 -07002023 struct qseecom_client_listener_data_irsp send_data_rsp = {0};
2024 struct qseecom_client_listener_data_64bit_irsp send_data_rsp_64bit
2025 = {0};
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07002026 struct qseecom_registered_listener_list *ptr_svc = NULL;
2027 sigset_t new_sigset;
2028 sigset_t old_sigset;
2029 uint32_t status;
2030 void *cmd_buf = NULL;
2031 size_t cmd_len;
2032 struct sglist_info *table = NULL;
2033
Zhen Kong26e62742018-05-04 17:19:06 -07002034 while (ret == 0 && resp->result == QSEOS_RESULT_INCOMPLETE) {
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07002035 lstnr = resp->data;
2036 /*
2037 * Wake up blocking lsitener service with the lstnr id
2038 */
Zhen Kongbcdeda22018-11-16 13:50:51 -08002039 mutex_lock(&listener_access_lock);
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07002040 list_for_each_entry(ptr_svc,
2041 &qseecom.registered_listener_list_head, list) {
2042 if (ptr_svc->svc.listener_id == lstnr) {
2043 ptr_svc->listener_in_use = true;
2044 ptr_svc->rcv_req_flag = 1;
2045 wake_up_interruptible(&ptr_svc->rcv_req_wq);
2046 break;
2047 }
2048 }
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07002049
2050 if (ptr_svc == NULL) {
2051 pr_err("Listener Svc %d does not exist\n", lstnr);
Zhen Kong26e62742018-05-04 17:19:06 -07002052 rc = -EINVAL;
2053 status = QSEOS_RESULT_FAILURE;
2054 goto err_resp;
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07002055 }
2056
2057 if (!ptr_svc->ihandle) {
2058 pr_err("Client handle is not initialized\n");
Zhen Kong26e62742018-05-04 17:19:06 -07002059 rc = -EINVAL;
2060 status = QSEOS_RESULT_FAILURE;
2061 goto err_resp;
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07002062 }
2063
2064 if (ptr_svc->svc.listener_id != lstnr) {
Zhen Kong26e62742018-05-04 17:19:06 -07002065 pr_err("Service %d does not exist\n",
2066 lstnr);
2067 rc = -ERESTARTSYS;
2068 ptr_svc = NULL;
2069 status = QSEOS_RESULT_FAILURE;
2070 goto err_resp;
2071 }
2072
2073 if (ptr_svc->abort == 1) {
Zhen Kongbcdeda22018-11-16 13:50:51 -08002074 pr_debug("Service %d abort %d\n",
Zhen Kong26e62742018-05-04 17:19:06 -07002075 lstnr, ptr_svc->abort);
2076 rc = -ENODEV;
2077 status = QSEOS_RESULT_FAILURE;
2078 goto err_resp;
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07002079 }
Zhen Kong25731112018-09-20 13:10:03 -07002080
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07002081 pr_debug("waking up rcv_req_wq and waiting for send_resp_wq\n");
2082
2083 /* initialize the new signal mask with all signals*/
2084 sigfillset(&new_sigset);
2085
2086 /* block all signals */
2087 sigprocmask(SIG_SETMASK, &new_sigset, &old_sigset);
2088
2089 /* unlock mutex btw waking listener and sleep-wait */
Zhen Kongbcdeda22018-11-16 13:50:51 -08002090 mutex_unlock(&listener_access_lock);
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07002091 mutex_unlock(&app_access_lock);
2092 do {
2093 if (!wait_event_freezable(qseecom.send_resp_wq,
2094 __qseecom_reentrancy_listener_has_sent_rsp(
2095 data, ptr_svc))) {
2096 break;
2097 }
2098 } while (1);
2099 /* lock mutex again after resp sent */
2100 mutex_lock(&app_access_lock);
Zhen Kongbcdeda22018-11-16 13:50:51 -08002101 mutex_lock(&listener_access_lock);
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07002102 ptr_svc->send_resp_flag = 0;
2103 qseecom.send_resp_flag = 0;
2104
2105 /* restore signal mask */
2106 sigprocmask(SIG_SETMASK, &old_sigset, NULL);
Zhen Kong26e62742018-05-04 17:19:06 -07002107 if (data->abort || ptr_svc->abort) {
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07002108 pr_err("Abort clnt %d waiting on lstnr svc %d, ret %d",
2109 data->client.app_id, lstnr, ret);
2110 rc = -ENODEV;
2111 status = QSEOS_RESULT_FAILURE;
2112 } else {
2113 status = QSEOS_RESULT_SUCCESS;
2114 }
Zhen Kong26e62742018-05-04 17:19:06 -07002115err_resp:
Zhen Kong7d500032018-08-06 16:58:31 -07002116 if (ptr_svc)
2117 table = ptr_svc->sglistinfo_ptr;
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07002118 if (qseecom.qsee_version < QSEE_VERSION_40) {
2119 send_data_rsp.listener_id = lstnr;
2120 send_data_rsp.status = status;
Zhen Kong7d500032018-08-06 16:58:31 -07002121 if (table) {
2122 send_data_rsp.sglistinfo_ptr =
2123 (uint32_t)virt_to_phys(table);
2124 send_data_rsp.sglistinfo_len =
2125 SGLISTINFO_TABLE_SIZE;
2126 dmac_flush_range((void *)table,
2127 (void *)table + SGLISTINFO_TABLE_SIZE);
2128 }
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07002129 cmd_buf = (void *)&send_data_rsp;
2130 cmd_len = sizeof(send_data_rsp);
2131 } else {
2132 send_data_rsp_64bit.listener_id = lstnr;
2133 send_data_rsp_64bit.status = status;
Zhen Kong7d500032018-08-06 16:58:31 -07002134 if (table) {
2135 send_data_rsp_64bit.sglistinfo_ptr =
2136 virt_to_phys(table);
2137 send_data_rsp_64bit.sglistinfo_len =
2138 SGLISTINFO_TABLE_SIZE;
2139 dmac_flush_range((void *)table,
2140 (void *)table + SGLISTINFO_TABLE_SIZE);
2141 }
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07002142 cmd_buf = (void *)&send_data_rsp_64bit;
2143 cmd_len = sizeof(send_data_rsp_64bit);
2144 }
Zhen Kong7d500032018-08-06 16:58:31 -07002145 if (qseecom.whitelist_support == false || table == NULL)
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07002146 *(uint32_t *)cmd_buf = QSEOS_LISTENER_DATA_RSP_COMMAND;
2147 else
2148 *(uint32_t *)cmd_buf =
2149 QSEOS_LISTENER_DATA_RSP_COMMAND_WHITELIST;
Zhen Kong4b8af612018-11-03 17:01:11 -07002150 if (ptr_svc && ptr_svc->ihandle) {
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07002151 ret = msm_ion_do_cache_op(qseecom.ion_clnt,
2152 ptr_svc->ihandle,
2153 ptr_svc->sb_virt, ptr_svc->sb_length,
2154 ION_IOC_CLEAN_INV_CACHES);
2155 if (ret) {
2156 pr_err("cache operation failed %d\n", ret);
2157 return ret;
2158 }
2159 }
2160 if (lstnr == RPMB_SERVICE) {
2161 ret = __qseecom_enable_clk(CLK_QSEE);
2162 if (ret)
Zhen Kongbcdeda22018-11-16 13:50:51 -08002163 goto exit;
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07002164 }
2165
2166 ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1,
2167 cmd_buf, cmd_len, resp, sizeof(*resp));
Zhen Kong7d500032018-08-06 16:58:31 -07002168 if (ptr_svc) {
2169 ptr_svc->listener_in_use = false;
2170 __qseecom_clean_listener_sglistinfo(ptr_svc);
2171 wake_up_interruptible(&ptr_svc->listener_block_app_wq);
2172 }
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07002173
2174 if (ret) {
2175 pr_err("scm_call() failed with err: %d (app_id = %d)\n",
2176 ret, data->client.app_id);
2177 goto exit;
2178 }
2179
2180 switch (resp->result) {
2181 case QSEOS_RESULT_BLOCKED_ON_LISTENER:
2182 pr_warn("send lsr %d rsp, but app %d block on lsr %d\n",
2183 lstnr, data->client.app_id, resp->data);
2184 if (lstnr == resp->data) {
2185 pr_err("lstnr %d should not be blocked!\n",
2186 lstnr);
2187 ret = -EINVAL;
2188 goto exit;
2189 }
Zhen Kong87dcf0e2019-01-04 12:34:50 -08002190 mutex_unlock(&listener_access_lock);
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07002191 ret = __qseecom_process_reentrancy_blocked_on_listener(
2192 resp, NULL, data);
Zhen Kong87dcf0e2019-01-04 12:34:50 -08002193 mutex_lock(&listener_access_lock);
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07002194 if (ret) {
2195 pr_err("failed to process App(%d) %s blocked on listener %d\n",
2196 data->client.app_id,
2197 data->client.app_name, resp->data);
2198 goto exit;
2199 }
2200 case QSEOS_RESULT_SUCCESS:
2201 case QSEOS_RESULT_INCOMPLETE:
2202 break;
2203 default:
2204 pr_err("fail:resp res= %d,app_id = %d,lstr = %d\n",
2205 resp->result, data->client.app_id, lstnr);
2206 ret = -EINVAL;
2207 goto exit;
2208 }
2209exit:
Zhen Kongbcdeda22018-11-16 13:50:51 -08002210 mutex_unlock(&listener_access_lock);
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07002211 if (lstnr == RPMB_SERVICE)
2212 __qseecom_disable_clk(CLK_QSEE);
2213
2214 }
2215 if (rc)
2216 return rc;
2217
2218 return ret;
2219}
2220
2221/*
2222 * QSEE doesn't support OS level cmds reentrancy until RE phase-3,
2223 * and QSEE OS level scm_call cmds will fail if there is any blocked TZ app.
2224 * So, needs to first check if no app blocked before sending OS level scm call,
2225 * then wait until all apps are unblocked.
2226 */
2227static void __qseecom_reentrancy_check_if_no_app_blocked(uint32_t smc_id)
2228{
2229 sigset_t new_sigset, old_sigset;
2230
2231 if (qseecom.qsee_reentrancy_support > QSEE_REENTRANCY_PHASE_0 &&
2232 qseecom.qsee_reentrancy_support < QSEE_REENTRANCY_PHASE_3 &&
2233 IS_OWNER_TRUSTED_OS(TZ_SYSCALL_OWNER_ID(smc_id))) {
2234 /* thread sleep until this app unblocked */
2235 while (qseecom.app_block_ref_cnt > 0) {
2236 sigfillset(&new_sigset);
2237 sigprocmask(SIG_SETMASK, &new_sigset, &old_sigset);
2238 mutex_unlock(&app_access_lock);
2239 do {
2240 if (!wait_event_freezable(qseecom.app_block_wq,
2241 (qseecom.app_block_ref_cnt == 0)))
2242 break;
2243 } while (1);
2244 mutex_lock(&app_access_lock);
2245 sigprocmask(SIG_SETMASK, &old_sigset, NULL);
2246 }
2247 }
2248}
2249
2250/*
2251 * scm_call of send data will fail if this TA is blocked or there are more
2252 * than one TA requesting listener services; So, first check to see if need
2253 * to wait.
2254 */
2255static void __qseecom_reentrancy_check_if_this_app_blocked(
2256 struct qseecom_registered_app_list *ptr_app)
2257{
2258 sigset_t new_sigset, old_sigset;
2259
2260 if (qseecom.qsee_reentrancy_support) {
Zhen Kongdea10592018-07-30 17:50:10 -07002261 ptr_app->check_block++;
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07002262 while (ptr_app->app_blocked || qseecom.app_block_ref_cnt > 1) {
2263 /* thread sleep until this app unblocked */
2264 sigfillset(&new_sigset);
2265 sigprocmask(SIG_SETMASK, &new_sigset, &old_sigset);
2266 mutex_unlock(&app_access_lock);
2267 do {
2268 if (!wait_event_freezable(qseecom.app_block_wq,
2269 (!ptr_app->app_blocked &&
2270 qseecom.app_block_ref_cnt <= 1)))
2271 break;
2272 } while (1);
2273 mutex_lock(&app_access_lock);
2274 sigprocmask(SIG_SETMASK, &old_sigset, NULL);
2275 }
Zhen Kongdea10592018-07-30 17:50:10 -07002276 ptr_app->check_block--;
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07002277 }
2278}
2279
2280static int __qseecom_check_app_exists(struct qseecom_check_app_ireq req,
2281 uint32_t *app_id)
2282{
2283 int32_t ret;
2284 struct qseecom_command_scm_resp resp;
2285 bool found_app = false;
2286 struct qseecom_registered_app_list *entry = NULL;
2287 unsigned long flags = 0;
2288
2289 if (!app_id) {
2290 pr_err("Null pointer to app_id\n");
2291 return -EINVAL;
2292 }
2293 *app_id = 0;
2294
2295 /* check if app exists and has been registered locally */
2296 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
2297 list_for_each_entry(entry,
2298 &qseecom.registered_app_list_head, list) {
2299 if (!strcmp(entry->app_name, req.app_name)) {
2300 found_app = true;
2301 break;
2302 }
2303 }
2304 spin_unlock_irqrestore(&qseecom.registered_app_list_lock, flags);
2305 if (found_app) {
2306 pr_debug("Found app with id %d\n", entry->app_id);
2307 *app_id = entry->app_id;
2308 return 0;
2309 }
2310
2311 memset((void *)&resp, 0, sizeof(resp));
2312
2313 /* SCM_CALL to check if app_id for the mentioned app exists */
2314 ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
2315 sizeof(struct qseecom_check_app_ireq),
2316 &resp, sizeof(resp));
2317 if (ret) {
2318 pr_err("scm_call to check if app is already loaded failed\n");
2319 return -EINVAL;
2320 }
2321
2322 if (resp.result == QSEOS_RESULT_FAILURE)
2323 return 0;
2324
2325 switch (resp.resp_type) {
2326 /*qsee returned listener type response */
2327 case QSEOS_LISTENER_ID:
2328 pr_err("resp type is of listener type instead of app");
2329 return -EINVAL;
2330 case QSEOS_APP_ID:
2331 *app_id = resp.data;
2332 return 0;
2333 default:
2334 pr_err("invalid resp type (%d) from qsee",
2335 resp.resp_type);
2336 return -ENODEV;
2337 }
2338}
2339
2340static int qseecom_load_app(struct qseecom_dev_handle *data, void __user *argp)
2341{
2342 struct qseecom_registered_app_list *entry = NULL;
2343 unsigned long flags = 0;
2344 u32 app_id = 0;
2345 struct ion_handle *ihandle; /* Ion handle */
2346 struct qseecom_load_img_req load_img_req;
2347 int32_t ret = 0;
2348 ion_phys_addr_t pa = 0;
2349 size_t len;
2350 struct qseecom_command_scm_resp resp;
2351 struct qseecom_check_app_ireq req;
2352 struct qseecom_load_app_ireq load_req;
2353 struct qseecom_load_app_64bit_ireq load_req_64bit;
2354 void *cmd_buf = NULL;
2355 size_t cmd_len;
2356 bool first_time = false;
2357
2358 /* Copy the relevant information needed for loading the image */
2359 if (copy_from_user(&load_img_req,
2360 (void __user *)argp,
2361 sizeof(struct qseecom_load_img_req))) {
2362 pr_err("copy_from_user failed\n");
2363 return -EFAULT;
2364 }
2365
2366 /* Check and load cmnlib */
2367 if (qseecom.qsee_version > QSEEE_VERSION_00) {
2368 if (!qseecom.commonlib_loaded &&
2369 load_img_req.app_arch == ELFCLASS32) {
2370 ret = qseecom_load_commonlib_image(data, "cmnlib");
2371 if (ret) {
2372 pr_err("failed to load cmnlib\n");
2373 return -EIO;
2374 }
2375 qseecom.commonlib_loaded = true;
2376 pr_debug("cmnlib is loaded\n");
2377 }
2378
2379 if (!qseecom.commonlib64_loaded &&
2380 load_img_req.app_arch == ELFCLASS64) {
2381 ret = qseecom_load_commonlib_image(data, "cmnlib64");
2382 if (ret) {
2383 pr_err("failed to load cmnlib64\n");
2384 return -EIO;
2385 }
2386 qseecom.commonlib64_loaded = true;
2387 pr_debug("cmnlib64 is loaded\n");
2388 }
2389 }
2390
2391 if (qseecom.support_bus_scaling) {
2392 mutex_lock(&qsee_bw_mutex);
2393 ret = __qseecom_register_bus_bandwidth_needs(data, MEDIUM);
2394 mutex_unlock(&qsee_bw_mutex);
2395 if (ret)
2396 return ret;
2397 }
2398
2399 /* Vote for the SFPB clock */
2400 ret = __qseecom_enable_clk_scale_up(data);
2401 if (ret)
2402 goto enable_clk_err;
2403
2404 req.qsee_cmd_id = QSEOS_APP_LOOKUP_COMMAND;
2405 load_img_req.img_name[MAX_APP_NAME_SIZE-1] = '\0';
2406 strlcpy(req.app_name, load_img_req.img_name, MAX_APP_NAME_SIZE);
2407
2408 ret = __qseecom_check_app_exists(req, &app_id);
2409 if (ret < 0)
2410 goto loadapp_err;
2411
2412 if (app_id) {
2413 pr_debug("App id %d (%s) already exists\n", app_id,
2414 (char *)(req.app_name));
2415 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
2416 list_for_each_entry(entry,
2417 &qseecom.registered_app_list_head, list){
2418 if (entry->app_id == app_id) {
2419 entry->ref_cnt++;
2420 break;
2421 }
2422 }
2423 spin_unlock_irqrestore(
2424 &qseecom.registered_app_list_lock, flags);
2425 ret = 0;
2426 } else {
2427 first_time = true;
2428 pr_warn("App (%s) does'nt exist, loading apps for first time\n",
2429 (char *)(load_img_req.img_name));
2430 /* Get the handle of the shared fd */
AnilKumar Chimata04d60cf2017-04-09 11:43:10 -07002431 ihandle = ion_import_dma_buf_fd(qseecom.ion_clnt,
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07002432 load_img_req.ifd_data_fd);
2433 if (IS_ERR_OR_NULL(ihandle)) {
2434 pr_err("Ion client could not retrieve the handle\n");
2435 ret = -ENOMEM;
2436 goto loadapp_err;
2437 }
2438
2439 /* Get the physical address of the ION BUF */
2440 ret = ion_phys(qseecom.ion_clnt, ihandle, &pa, &len);
2441 if (ret) {
2442 pr_err("Cannot get phys_addr for the Ion Client, ret = %d\n",
2443 ret);
2444 goto loadapp_err;
2445 }
2446 if (load_img_req.mdt_len > len || load_img_req.img_len > len) {
2447 pr_err("ion len %zu is smaller than mdt_len %u or img_len %u\n",
2448 len, load_img_req.mdt_len,
2449 load_img_req.img_len);
2450 ret = -EINVAL;
2451 goto loadapp_err;
2452 }
2453 /* Populate the structure for sending scm call to load image */
2454 if (qseecom.qsee_version < QSEE_VERSION_40) {
2455 load_req.qsee_cmd_id = QSEOS_APP_START_COMMAND;
2456 load_req.mdt_len = load_img_req.mdt_len;
2457 load_req.img_len = load_img_req.img_len;
2458 strlcpy(load_req.app_name, load_img_req.img_name,
2459 MAX_APP_NAME_SIZE);
2460 load_req.phy_addr = (uint32_t)pa;
2461 cmd_buf = (void *)&load_req;
2462 cmd_len = sizeof(struct qseecom_load_app_ireq);
2463 } else {
2464 load_req_64bit.qsee_cmd_id = QSEOS_APP_START_COMMAND;
2465 load_req_64bit.mdt_len = load_img_req.mdt_len;
2466 load_req_64bit.img_len = load_img_req.img_len;
2467 strlcpy(load_req_64bit.app_name, load_img_req.img_name,
2468 MAX_APP_NAME_SIZE);
2469 load_req_64bit.phy_addr = (uint64_t)pa;
2470 cmd_buf = (void *)&load_req_64bit;
2471 cmd_len = sizeof(struct qseecom_load_app_64bit_ireq);
2472 }
2473
2474 ret = msm_ion_do_cache_op(qseecom.ion_clnt, ihandle, NULL, len,
2475 ION_IOC_CLEAN_INV_CACHES);
2476 if (ret) {
2477 pr_err("cache operation failed %d\n", ret);
2478 goto loadapp_err;
2479 }
2480
2481 /* SCM_CALL to load the app and get the app_id back */
2482 ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, cmd_buf,
2483 cmd_len, &resp, sizeof(resp));
2484 if (ret) {
2485 pr_err("scm_call to load app failed\n");
2486 if (!IS_ERR_OR_NULL(ihandle))
2487 ion_free(qseecom.ion_clnt, ihandle);
2488 ret = -EINVAL;
2489 goto loadapp_err;
2490 }
2491
2492 if (resp.result == QSEOS_RESULT_FAILURE) {
2493 pr_err("scm_call rsp.result is QSEOS_RESULT_FAILURE\n");
2494 if (!IS_ERR_OR_NULL(ihandle))
2495 ion_free(qseecom.ion_clnt, ihandle);
2496 ret = -EFAULT;
2497 goto loadapp_err;
2498 }
2499
2500 if (resp.result == QSEOS_RESULT_INCOMPLETE) {
2501 ret = __qseecom_process_incomplete_cmd(data, &resp);
2502 if (ret) {
2503 pr_err("process_incomplete_cmd failed err: %d\n",
2504 ret);
2505 if (!IS_ERR_OR_NULL(ihandle))
2506 ion_free(qseecom.ion_clnt, ihandle);
2507 ret = -EFAULT;
2508 goto loadapp_err;
2509 }
2510 }
2511
2512 if (resp.result != QSEOS_RESULT_SUCCESS) {
2513 pr_err("scm_call failed resp.result unknown, %d\n",
2514 resp.result);
2515 if (!IS_ERR_OR_NULL(ihandle))
2516 ion_free(qseecom.ion_clnt, ihandle);
2517 ret = -EFAULT;
2518 goto loadapp_err;
2519 }
2520
2521 app_id = resp.data;
2522
2523 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
2524 if (!entry) {
2525 ret = -ENOMEM;
2526 goto loadapp_err;
2527 }
2528 entry->app_id = app_id;
2529 entry->ref_cnt = 1;
2530 entry->app_arch = load_img_req.app_arch;
2531 /*
2532 * keymaster app may be first loaded as "keymaste" by qseecomd,
2533 * and then used as "keymaster" on some targets. To avoid app
2534 * name checking error, register "keymaster" into app_list and
2535 * thread private data.
2536 */
2537 if (!strcmp(load_img_req.img_name, "keymaste"))
2538 strlcpy(entry->app_name, "keymaster",
2539 MAX_APP_NAME_SIZE);
2540 else
2541 strlcpy(entry->app_name, load_img_req.img_name,
2542 MAX_APP_NAME_SIZE);
2543 entry->app_blocked = false;
2544 entry->blocked_on_listener_id = 0;
Zhen Kongdea10592018-07-30 17:50:10 -07002545 entry->check_block = 0;
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07002546
2547 /* Deallocate the handle */
2548 if (!IS_ERR_OR_NULL(ihandle))
2549 ion_free(qseecom.ion_clnt, ihandle);
2550
2551 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
2552 list_add_tail(&entry->list, &qseecom.registered_app_list_head);
2553 spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
2554 flags);
2555
2556 pr_warn("App with id %u (%s) now loaded\n", app_id,
2557 (char *)(load_img_req.img_name));
2558 }
2559 data->client.app_id = app_id;
2560 data->client.app_arch = load_img_req.app_arch;
2561 if (!strcmp(load_img_req.img_name, "keymaste"))
2562 strlcpy(data->client.app_name, "keymaster", MAX_APP_NAME_SIZE);
2563 else
2564 strlcpy(data->client.app_name, load_img_req.img_name,
2565 MAX_APP_NAME_SIZE);
2566 load_img_req.app_id = app_id;
2567 if (copy_to_user(argp, &load_img_req, sizeof(load_img_req))) {
2568 pr_err("copy_to_user failed\n");
2569 ret = -EFAULT;
2570 if (first_time == true) {
2571 spin_lock_irqsave(
2572 &qseecom.registered_app_list_lock, flags);
2573 list_del(&entry->list);
2574 spin_unlock_irqrestore(
2575 &qseecom.registered_app_list_lock, flags);
2576 kzfree(entry);
2577 }
2578 }
2579
2580loadapp_err:
2581 __qseecom_disable_clk_scale_down(data);
2582enable_clk_err:
2583 if (qseecom.support_bus_scaling) {
2584 mutex_lock(&qsee_bw_mutex);
2585 qseecom_unregister_bus_bandwidth_needs(data);
2586 mutex_unlock(&qsee_bw_mutex);
2587 }
2588 return ret;
2589}
2590
2591static int __qseecom_cleanup_app(struct qseecom_dev_handle *data)
2592{
2593 int ret = 1; /* Set unload app */
2594
2595 wake_up_all(&qseecom.send_resp_wq);
2596 if (qseecom.qsee_reentrancy_support)
2597 mutex_unlock(&app_access_lock);
2598 while (atomic_read(&data->ioctl_count) > 1) {
2599 if (wait_event_freezable(data->abort_wq,
2600 atomic_read(&data->ioctl_count) <= 1)) {
2601 pr_err("Interrupted from abort\n");
2602 ret = -ERESTARTSYS;
2603 break;
2604 }
2605 }
2606 if (qseecom.qsee_reentrancy_support)
2607 mutex_lock(&app_access_lock);
2608 return ret;
2609}
2610
2611static int qseecom_unmap_ion_allocated_memory(struct qseecom_dev_handle *data)
2612{
2613 int ret = 0;
2614
2615 if (!IS_ERR_OR_NULL(data->client.ihandle)) {
2616 ion_unmap_kernel(qseecom.ion_clnt, data->client.ihandle);
2617 ion_free(qseecom.ion_clnt, data->client.ihandle);
2618 data->client.ihandle = NULL;
2619 }
2620 return ret;
2621}
2622
2623static int qseecom_unload_app(struct qseecom_dev_handle *data,
2624 bool app_crash)
2625{
2626 unsigned long flags;
2627 unsigned long flags1;
2628 int ret = 0;
2629 struct qseecom_command_scm_resp resp;
2630 struct qseecom_registered_app_list *ptr_app = NULL;
2631 bool unload = false;
2632 bool found_app = false;
2633 bool found_dead_app = false;
2634
2635 if (!data) {
2636 pr_err("Invalid/uninitialized device handle\n");
2637 return -EINVAL;
2638 }
2639
2640 if (!memcmp(data->client.app_name, "keymaste", strlen("keymaste"))) {
2641 pr_debug("Do not unload keymaster app from tz\n");
2642 goto unload_exit;
2643 }
2644
2645 __qseecom_cleanup_app(data);
2646 __qseecom_reentrancy_check_if_no_app_blocked(TZ_OS_APP_SHUTDOWN_ID);
2647
2648 if (data->client.app_id > 0) {
2649 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
2650 list_for_each_entry(ptr_app, &qseecom.registered_app_list_head,
2651 list) {
2652 if (ptr_app->app_id == data->client.app_id) {
2653 if (!strcmp((void *)ptr_app->app_name,
2654 (void *)data->client.app_name)) {
2655 found_app = true;
Zhen Kong024798b2018-07-13 18:14:26 -07002656 if (ptr_app->app_blocked ||
2657 ptr_app->check_block)
Zhen Kongaf93d7a2017-10-13 14:01:48 -07002658 app_crash = false;
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07002659 if (app_crash || ptr_app->ref_cnt == 1)
2660 unload = true;
2661 break;
2662 }
2663 found_dead_app = true;
2664 break;
2665 }
2666 }
2667 spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
2668 flags);
2669 if (found_app == false && found_dead_app == false) {
2670 pr_err("Cannot find app with id = %d (%s)\n",
2671 data->client.app_id,
2672 (char *)data->client.app_name);
2673 ret = -EINVAL;
2674 goto unload_exit;
2675 }
2676 }
2677
2678 if (found_dead_app)
2679 pr_warn("cleanup app_id %d(%s)\n", data->client.app_id,
2680 (char *)data->client.app_name);
2681
2682 if (unload) {
2683 struct qseecom_unload_app_ireq req;
2684 /* Populate the structure for sending scm call to load image */
2685 req.qsee_cmd_id = QSEOS_APP_SHUTDOWN_COMMAND;
2686 req.app_id = data->client.app_id;
2687
2688 /* SCM_CALL to unload the app */
2689 ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
2690 sizeof(struct qseecom_unload_app_ireq),
2691 &resp, sizeof(resp));
2692 if (ret) {
2693 pr_err("scm_call to unload app (id = %d) failed\n",
2694 req.app_id);
2695 ret = -EFAULT;
2696 goto unload_exit;
2697 } else {
2698 pr_warn("App id %d now unloaded\n", req.app_id);
2699 }
2700 if (resp.result == QSEOS_RESULT_FAILURE) {
2701 pr_err("app (%d) unload_failed!!\n",
2702 data->client.app_id);
2703 ret = -EFAULT;
2704 goto unload_exit;
2705 }
2706 if (resp.result == QSEOS_RESULT_SUCCESS)
2707 pr_debug("App (%d) is unloaded!!\n",
2708 data->client.app_id);
2709 if (resp.result == QSEOS_RESULT_INCOMPLETE) {
2710 ret = __qseecom_process_incomplete_cmd(data, &resp);
2711 if (ret) {
2712 pr_err("process_incomplete_cmd fail err: %d\n",
2713 ret);
2714 goto unload_exit;
2715 }
2716 }
2717 }
2718
Zhen Kong7d500032018-08-06 16:58:31 -07002719unload_exit:
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07002720 if (found_app) {
2721 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags1);
2722 if (app_crash) {
2723 ptr_app->ref_cnt = 0;
2724 pr_debug("app_crash: ref_count = 0\n");
2725 } else {
2726 if (ptr_app->ref_cnt == 1) {
2727 ptr_app->ref_cnt = 0;
2728 pr_debug("ref_count set to 0\n");
2729 } else {
2730 ptr_app->ref_cnt--;
2731 pr_debug("Can't unload app(%d) inuse\n",
2732 ptr_app->app_id);
2733 }
2734 }
2735 if (unload) {
2736 list_del(&ptr_app->list);
2737 kzfree(ptr_app);
2738 }
2739 spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
2740 flags1);
2741 }
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07002742 qseecom_unmap_ion_allocated_memory(data);
2743 data->released = true;
2744 return ret;
2745}
2746
2747static phys_addr_t __qseecom_uvirt_to_kphys(struct qseecom_dev_handle *data,
2748 unsigned long virt)
2749{
2750 return data->client.sb_phys + (virt - data->client.user_virt_sb_base);
2751}
2752
2753static uintptr_t __qseecom_uvirt_to_kvirt(struct qseecom_dev_handle *data,
2754 unsigned long virt)
2755{
2756 return (uintptr_t)data->client.sb_virt +
2757 (virt - data->client.user_virt_sb_base);
2758}
2759
2760int __qseecom_process_rpmb_svc_cmd(struct qseecom_dev_handle *data_ptr,
2761 struct qseecom_send_svc_cmd_req *req_ptr,
2762 struct qseecom_client_send_service_ireq *send_svc_ireq_ptr)
2763{
2764 int ret = 0;
2765 void *req_buf = NULL;
2766
2767 if ((req_ptr == NULL) || (send_svc_ireq_ptr == NULL)) {
2768 pr_err("Error with pointer: req_ptr = %pK, send_svc_ptr = %pK\n",
2769 req_ptr, send_svc_ireq_ptr);
2770 return -EINVAL;
2771 }
2772
2773 /* Clients need to ensure req_buf is at base offset of shared buffer */
2774 if ((uintptr_t)req_ptr->cmd_req_buf !=
2775 data_ptr->client.user_virt_sb_base) {
2776 pr_err("cmd buf not pointing to base offset of shared buffer\n");
2777 return -EINVAL;
2778 }
2779
2780 if (data_ptr->client.sb_length <
2781 sizeof(struct qseecom_rpmb_provision_key)) {
2782 pr_err("shared buffer is too small to hold key type\n");
2783 return -EINVAL;
2784 }
2785 req_buf = data_ptr->client.sb_virt;
2786
2787 send_svc_ireq_ptr->qsee_cmd_id = req_ptr->cmd_id;
2788 send_svc_ireq_ptr->key_type =
2789 ((struct qseecom_rpmb_provision_key *)req_buf)->key_type;
2790 send_svc_ireq_ptr->req_len = req_ptr->cmd_req_len;
2791 send_svc_ireq_ptr->rsp_ptr = (uint32_t)(__qseecom_uvirt_to_kphys(
2792 data_ptr, (uintptr_t)req_ptr->resp_buf));
2793 send_svc_ireq_ptr->rsp_len = req_ptr->resp_len;
2794
2795 return ret;
2796}
2797
2798int __qseecom_process_fsm_key_svc_cmd(struct qseecom_dev_handle *data_ptr,
2799 struct qseecom_send_svc_cmd_req *req_ptr,
2800 struct qseecom_client_send_fsm_key_req *send_svc_ireq_ptr)
2801{
2802 int ret = 0;
2803 uint32_t reqd_len_sb_in = 0;
2804
2805 if ((req_ptr == NULL) || (send_svc_ireq_ptr == NULL)) {
2806 pr_err("Error with pointer: req_ptr = %pK, send_svc_ptr = %pK\n",
2807 req_ptr, send_svc_ireq_ptr);
2808 return -EINVAL;
2809 }
2810
2811 reqd_len_sb_in = req_ptr->cmd_req_len + req_ptr->resp_len;
2812 if (reqd_len_sb_in > data_ptr->client.sb_length) {
2813 pr_err("Not enough memory to fit cmd_buf and resp_buf. ");
2814 pr_err("Required: %u, Available: %zu\n",
2815 reqd_len_sb_in, data_ptr->client.sb_length);
2816 return -ENOMEM;
2817 }
2818
2819 send_svc_ireq_ptr->qsee_cmd_id = req_ptr->cmd_id;
2820 send_svc_ireq_ptr->req_len = req_ptr->cmd_req_len;
2821 send_svc_ireq_ptr->rsp_ptr = (uint32_t)(__qseecom_uvirt_to_kphys(
2822 data_ptr, (uintptr_t)req_ptr->resp_buf));
2823 send_svc_ireq_ptr->rsp_len = req_ptr->resp_len;
2824
2825 send_svc_ireq_ptr->req_ptr = (uint32_t)(__qseecom_uvirt_to_kphys(
2826 data_ptr, (uintptr_t)req_ptr->cmd_req_buf));
2827
2828
2829 return ret;
2830}
2831
2832static int __validate_send_service_cmd_inputs(struct qseecom_dev_handle *data,
2833 struct qseecom_send_svc_cmd_req *req)
2834{
2835 if (!req || !req->resp_buf || !req->cmd_req_buf) {
2836 pr_err("req or cmd buffer or response buffer is null\n");
2837 return -EINVAL;
2838 }
2839
2840 if (!data || !data->client.ihandle) {
2841 pr_err("Client or client handle is not initialized\n");
2842 return -EINVAL;
2843 }
2844
2845 if (data->client.sb_virt == NULL) {
2846 pr_err("sb_virt null\n");
2847 return -EINVAL;
2848 }
2849
2850 if (data->client.user_virt_sb_base == 0) {
2851 pr_err("user_virt_sb_base is null\n");
2852 return -EINVAL;
2853 }
2854
2855 if (data->client.sb_length == 0) {
2856 pr_err("sb_length is 0\n");
2857 return -EINVAL;
2858 }
2859
2860 if (((uintptr_t)req->cmd_req_buf <
2861 data->client.user_virt_sb_base) ||
2862 ((uintptr_t)req->cmd_req_buf >=
2863 (data->client.user_virt_sb_base + data->client.sb_length))) {
2864 pr_err("cmd buffer address not within shared bufffer\n");
2865 return -EINVAL;
2866 }
2867 if (((uintptr_t)req->resp_buf <
2868 data->client.user_virt_sb_base) ||
2869 ((uintptr_t)req->resp_buf >=
2870 (data->client.user_virt_sb_base + data->client.sb_length))) {
2871 pr_err("response buffer address not within shared bufffer\n");
2872 return -EINVAL;
2873 }
2874 if ((req->cmd_req_len == 0) || (req->resp_len == 0) ||
2875 (req->cmd_req_len > data->client.sb_length) ||
2876 (req->resp_len > data->client.sb_length)) {
2877 pr_err("cmd buf length or response buf length not valid\n");
2878 return -EINVAL;
2879 }
2880 if (req->cmd_req_len > UINT_MAX - req->resp_len) {
2881 pr_err("Integer overflow detected in req_len & rsp_len\n");
2882 return -EINVAL;
2883 }
2884
2885 if ((req->cmd_req_len + req->resp_len) > data->client.sb_length) {
2886 pr_debug("Not enough memory to fit cmd_buf.\n");
2887 pr_debug("resp_buf. Required: %u, Available: %zu\n",
2888 (req->cmd_req_len + req->resp_len),
2889 data->client.sb_length);
2890 return -ENOMEM;
2891 }
2892 if ((uintptr_t)req->cmd_req_buf > (ULONG_MAX - req->cmd_req_len)) {
2893 pr_err("Integer overflow in req_len & cmd_req_buf\n");
2894 return -EINVAL;
2895 }
2896 if ((uintptr_t)req->resp_buf > (ULONG_MAX - req->resp_len)) {
2897 pr_err("Integer overflow in resp_len & resp_buf\n");
2898 return -EINVAL;
2899 }
2900 if (data->client.user_virt_sb_base >
2901 (ULONG_MAX - data->client.sb_length)) {
2902 pr_err("Integer overflow in user_virt_sb_base & sb_length\n");
2903 return -EINVAL;
2904 }
2905 if ((((uintptr_t)req->cmd_req_buf + req->cmd_req_len) >
2906 ((uintptr_t)data->client.user_virt_sb_base +
2907 data->client.sb_length)) ||
2908 (((uintptr_t)req->resp_buf + req->resp_len) >
2909 ((uintptr_t)data->client.user_virt_sb_base +
2910 data->client.sb_length))) {
2911 pr_err("cmd buf or resp buf is out of shared buffer region\n");
2912 return -EINVAL;
2913 }
2914 return 0;
2915}
2916
2917static int qseecom_send_service_cmd(struct qseecom_dev_handle *data,
2918 void __user *argp)
2919{
2920 int ret = 0;
2921 struct qseecom_client_send_service_ireq send_svc_ireq;
2922 struct qseecom_client_send_fsm_key_req send_fsm_key_svc_ireq;
2923 struct qseecom_command_scm_resp resp;
2924 struct qseecom_send_svc_cmd_req req;
2925 void *send_req_ptr;
2926 size_t req_buf_size;
2927
2928 /*struct qseecom_command_scm_resp resp;*/
2929
2930 if (copy_from_user(&req,
2931 (void __user *)argp,
2932 sizeof(req))) {
2933 pr_err("copy_from_user failed\n");
2934 return -EFAULT;
2935 }
2936
2937 if (__validate_send_service_cmd_inputs(data, &req))
2938 return -EINVAL;
2939
2940 data->type = QSEECOM_SECURE_SERVICE;
2941
2942 switch (req.cmd_id) {
2943 case QSEOS_RPMB_PROVISION_KEY_COMMAND:
2944 case QSEOS_RPMB_ERASE_COMMAND:
2945 case QSEOS_RPMB_CHECK_PROV_STATUS_COMMAND:
2946 send_req_ptr = &send_svc_ireq;
2947 req_buf_size = sizeof(send_svc_ireq);
2948 if (__qseecom_process_rpmb_svc_cmd(data, &req,
2949 send_req_ptr))
2950 return -EINVAL;
2951 break;
2952 case QSEOS_FSM_LTEOTA_REQ_CMD:
2953 case QSEOS_FSM_LTEOTA_REQ_RSP_CMD:
2954 case QSEOS_FSM_IKE_REQ_CMD:
2955 case QSEOS_FSM_IKE_REQ_RSP_CMD:
2956 case QSEOS_FSM_OEM_FUSE_WRITE_ROW:
2957 case QSEOS_FSM_OEM_FUSE_READ_ROW:
2958 case QSEOS_FSM_ENCFS_REQ_CMD:
2959 case QSEOS_FSM_ENCFS_REQ_RSP_CMD:
2960 send_req_ptr = &send_fsm_key_svc_ireq;
2961 req_buf_size = sizeof(send_fsm_key_svc_ireq);
2962 if (__qseecom_process_fsm_key_svc_cmd(data, &req,
2963 send_req_ptr))
2964 return -EINVAL;
2965 break;
2966 default:
2967 pr_err("Unsupported cmd_id %d\n", req.cmd_id);
2968 return -EINVAL;
2969 }
2970
2971 if (qseecom.support_bus_scaling) {
2972 ret = qseecom_scale_bus_bandwidth_timer(HIGH);
2973 if (ret) {
2974 pr_err("Fail to set bw HIGH\n");
2975 return ret;
2976 }
2977 } else {
2978 ret = qseecom_perf_enable(data);
2979 if (ret) {
2980 pr_err("Failed to vote for clocks with err %d\n", ret);
2981 goto exit;
2982 }
2983 }
2984
2985 ret = msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
2986 data->client.sb_virt, data->client.sb_length,
2987 ION_IOC_CLEAN_INV_CACHES);
2988 if (ret) {
2989 pr_err("cache operation failed %d\n", ret);
2990 goto exit;
2991 }
2992 ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1,
2993 (const void *)send_req_ptr,
2994 req_buf_size, &resp, sizeof(resp));
2995 if (ret) {
2996 pr_err("qseecom_scm_call failed with err: %d\n", ret);
2997 if (!qseecom.support_bus_scaling) {
2998 qsee_disable_clock_vote(data, CLK_DFAB);
2999 qsee_disable_clock_vote(data, CLK_SFPB);
3000 } else {
3001 __qseecom_add_bw_scale_down_timer(
3002 QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
3003 }
3004 goto exit;
3005 }
3006 ret = msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
3007 data->client.sb_virt, data->client.sb_length,
3008 ION_IOC_INV_CACHES);
3009 if (ret) {
3010 pr_err("cache operation failed %d\n", ret);
3011 goto exit;
3012 }
3013 switch (resp.result) {
3014 case QSEOS_RESULT_SUCCESS:
3015 break;
3016 case QSEOS_RESULT_INCOMPLETE:
3017 pr_debug("qseos_result_incomplete\n");
3018 ret = __qseecom_process_incomplete_cmd(data, &resp);
3019 if (ret) {
3020 pr_err("process_incomplete_cmd fail with result: %d\n",
3021 resp.result);
3022 }
3023 if (req.cmd_id == QSEOS_RPMB_CHECK_PROV_STATUS_COMMAND) {
3024 pr_warn("RPMB key status is 0x%x\n", resp.result);
Brahmaji Kb33e26e2017-06-01 17:20:10 +05303025 if (put_user(resp.result,
3026 (uint32_t __user *)req.resp_buf)) {
3027 ret = -EINVAL;
3028 goto exit;
3029 }
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07003030 ret = 0;
3031 }
3032 break;
3033 case QSEOS_RESULT_FAILURE:
3034 pr_err("scm call failed with resp.result: %d\n", resp.result);
3035 ret = -EINVAL;
3036 break;
3037 default:
3038 pr_err("Response result %d not supported\n",
3039 resp.result);
3040 ret = -EINVAL;
3041 break;
3042 }
3043 if (!qseecom.support_bus_scaling) {
3044 qsee_disable_clock_vote(data, CLK_DFAB);
3045 qsee_disable_clock_vote(data, CLK_SFPB);
3046 } else {
3047 __qseecom_add_bw_scale_down_timer(
3048 QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
3049 }
3050
3051exit:
3052 return ret;
3053}
3054
3055static int __validate_send_cmd_inputs(struct qseecom_dev_handle *data,
3056 struct qseecom_send_cmd_req *req)
3057
3058{
3059 if (!data || !data->client.ihandle) {
3060 pr_err("Client or client handle is not initialized\n");
3061 return -EINVAL;
3062 }
3063 if (((req->resp_buf == NULL) && (req->resp_len != 0)) ||
3064 (req->cmd_req_buf == NULL)) {
3065 pr_err("cmd buffer or response buffer is null\n");
3066 return -EINVAL;
3067 }
3068 if (((uintptr_t)req->cmd_req_buf <
3069 data->client.user_virt_sb_base) ||
3070 ((uintptr_t)req->cmd_req_buf >=
3071 (data->client.user_virt_sb_base + data->client.sb_length))) {
3072 pr_err("cmd buffer address not within shared bufffer\n");
3073 return -EINVAL;
3074 }
3075 if (((uintptr_t)req->resp_buf <
3076 data->client.user_virt_sb_base) ||
3077 ((uintptr_t)req->resp_buf >=
3078 (data->client.user_virt_sb_base + data->client.sb_length))) {
3079 pr_err("response buffer address not within shared bufffer\n");
3080 return -EINVAL;
3081 }
3082 if ((req->cmd_req_len == 0) ||
3083 (req->cmd_req_len > data->client.sb_length) ||
3084 (req->resp_len > data->client.sb_length)) {
3085 pr_err("cmd buf length or response buf length not valid\n");
3086 return -EINVAL;
3087 }
3088 if (req->cmd_req_len > UINT_MAX - req->resp_len) {
3089 pr_err("Integer overflow detected in req_len & rsp_len\n");
3090 return -EINVAL;
3091 }
3092
3093 if ((req->cmd_req_len + req->resp_len) > data->client.sb_length) {
3094 pr_debug("Not enough memory to fit cmd_buf.\n");
3095 pr_debug("resp_buf. Required: %u, Available: %zu\n",
3096 (req->cmd_req_len + req->resp_len),
3097 data->client.sb_length);
3098 return -ENOMEM;
3099 }
3100 if ((uintptr_t)req->cmd_req_buf > (ULONG_MAX - req->cmd_req_len)) {
3101 pr_err("Integer overflow in req_len & cmd_req_buf\n");
3102 return -EINVAL;
3103 }
3104 if ((uintptr_t)req->resp_buf > (ULONG_MAX - req->resp_len)) {
3105 pr_err("Integer overflow in resp_len & resp_buf\n");
3106 return -EINVAL;
3107 }
3108 if (data->client.user_virt_sb_base >
3109 (ULONG_MAX - data->client.sb_length)) {
3110 pr_err("Integer overflow in user_virt_sb_base & sb_length\n");
3111 return -EINVAL;
3112 }
3113 if ((((uintptr_t)req->cmd_req_buf + req->cmd_req_len) >
3114 ((uintptr_t)data->client.user_virt_sb_base +
3115 data->client.sb_length)) ||
3116 (((uintptr_t)req->resp_buf + req->resp_len) >
3117 ((uintptr_t)data->client.user_virt_sb_base +
3118 data->client.sb_length))) {
3119 pr_err("cmd buf or resp buf is out of shared buffer region\n");
3120 return -EINVAL;
3121 }
3122 return 0;
3123}
3124
3125int __qseecom_process_reentrancy(struct qseecom_command_scm_resp *resp,
3126 struct qseecom_registered_app_list *ptr_app,
3127 struct qseecom_dev_handle *data)
3128{
3129 int ret = 0;
3130
3131 switch (resp->result) {
3132 case QSEOS_RESULT_BLOCKED_ON_LISTENER:
3133 pr_warn("App(%d) %s is blocked on listener %d\n",
3134 data->client.app_id, data->client.app_name,
3135 resp->data);
3136 ret = __qseecom_process_reentrancy_blocked_on_listener(
3137 resp, ptr_app, data);
3138 if (ret) {
3139 pr_err("failed to process App(%d) %s is blocked on listener %d\n",
3140 data->client.app_id, data->client.app_name, resp->data);
3141 return ret;
3142 }
3143
3144 case QSEOS_RESULT_INCOMPLETE:
3145 qseecom.app_block_ref_cnt++;
3146 ptr_app->app_blocked = true;
3147 ret = __qseecom_reentrancy_process_incomplete_cmd(data, resp);
3148 ptr_app->app_blocked = false;
3149 qseecom.app_block_ref_cnt--;
3150 wake_up_interruptible(&qseecom.app_block_wq);
3151 if (ret)
3152 pr_err("process_incomplete_cmd failed err: %d\n",
3153 ret);
3154 return ret;
3155 case QSEOS_RESULT_SUCCESS:
3156 return ret;
3157 default:
3158 pr_err("Response result %d not supported\n",
3159 resp->result);
3160 return -EINVAL;
3161 }
3162}
3163
3164static int __qseecom_send_cmd(struct qseecom_dev_handle *data,
3165 struct qseecom_send_cmd_req *req)
3166{
3167 int ret = 0;
Zhen Kong4af480e2017-09-19 14:34:16 -07003168 int ret2 = 0;
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07003169 u32 reqd_len_sb_in = 0;
3170 struct qseecom_client_send_data_ireq send_data_req = {0};
3171 struct qseecom_client_send_data_64bit_ireq send_data_req_64bit = {0};
3172 struct qseecom_command_scm_resp resp;
3173 unsigned long flags;
3174 struct qseecom_registered_app_list *ptr_app;
3175 bool found_app = false;
3176 void *cmd_buf = NULL;
3177 size_t cmd_len;
3178 struct sglist_info *table = data->sglistinfo_ptr;
3179
3180 reqd_len_sb_in = req->cmd_req_len + req->resp_len;
3181 /* find app_id & img_name from list */
3182 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
3183 list_for_each_entry(ptr_app, &qseecom.registered_app_list_head,
3184 list) {
3185 if ((ptr_app->app_id == data->client.app_id) &&
3186 (!strcmp(ptr_app->app_name, data->client.app_name))) {
3187 found_app = true;
3188 break;
3189 }
3190 }
3191 spin_unlock_irqrestore(&qseecom.registered_app_list_lock, flags);
3192
3193 if (!found_app) {
3194 pr_err("app_id %d (%s) is not found\n", data->client.app_id,
3195 (char *)data->client.app_name);
3196 return -ENOENT;
3197 }
3198
3199 if (qseecom.qsee_version < QSEE_VERSION_40) {
3200 send_data_req.app_id = data->client.app_id;
3201 send_data_req.req_ptr = (uint32_t)(__qseecom_uvirt_to_kphys(
3202 data, (uintptr_t)req->cmd_req_buf));
3203 send_data_req.req_len = req->cmd_req_len;
3204 send_data_req.rsp_ptr = (uint32_t)(__qseecom_uvirt_to_kphys(
3205 data, (uintptr_t)req->resp_buf));
3206 send_data_req.rsp_len = req->resp_len;
3207 send_data_req.sglistinfo_ptr =
3208 (uint32_t)virt_to_phys(table);
3209 send_data_req.sglistinfo_len = SGLISTINFO_TABLE_SIZE;
3210 dmac_flush_range((void *)table,
3211 (void *)table + SGLISTINFO_TABLE_SIZE);
3212 cmd_buf = (void *)&send_data_req;
3213 cmd_len = sizeof(struct qseecom_client_send_data_ireq);
3214 } else {
3215 send_data_req_64bit.app_id = data->client.app_id;
3216 send_data_req_64bit.req_ptr = __qseecom_uvirt_to_kphys(data,
3217 (uintptr_t)req->cmd_req_buf);
3218 send_data_req_64bit.req_len = req->cmd_req_len;
3219 send_data_req_64bit.rsp_ptr = __qseecom_uvirt_to_kphys(data,
3220 (uintptr_t)req->resp_buf);
3221 send_data_req_64bit.rsp_len = req->resp_len;
3222 /* check if 32bit app's phys_addr region is under 4GB.*/
3223 if ((data->client.app_arch == ELFCLASS32) &&
3224 ((send_data_req_64bit.req_ptr >=
3225 PHY_ADDR_4G - send_data_req_64bit.req_len) ||
3226 (send_data_req_64bit.rsp_ptr >=
3227 PHY_ADDR_4G - send_data_req_64bit.rsp_len))){
3228 pr_err("32bit app %s PA exceeds 4G: req_ptr=%llx, req_len=%x, rsp_ptr=%llx, rsp_len=%x\n",
3229 data->client.app_name,
3230 send_data_req_64bit.req_ptr,
3231 send_data_req_64bit.req_len,
3232 send_data_req_64bit.rsp_ptr,
3233 send_data_req_64bit.rsp_len);
3234 return -EFAULT;
3235 }
3236 send_data_req_64bit.sglistinfo_ptr =
3237 (uint64_t)virt_to_phys(table);
3238 send_data_req_64bit.sglistinfo_len = SGLISTINFO_TABLE_SIZE;
3239 dmac_flush_range((void *)table,
3240 (void *)table + SGLISTINFO_TABLE_SIZE);
3241 cmd_buf = (void *)&send_data_req_64bit;
3242 cmd_len = sizeof(struct qseecom_client_send_data_64bit_ireq);
3243 }
3244
3245 if (qseecom.whitelist_support == false || data->use_legacy_cmd == true)
3246 *(uint32_t *)cmd_buf = QSEOS_CLIENT_SEND_DATA_COMMAND;
3247 else
3248 *(uint32_t *)cmd_buf = QSEOS_CLIENT_SEND_DATA_COMMAND_WHITELIST;
3249
3250 ret = msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
3251 data->client.sb_virt,
3252 reqd_len_sb_in,
3253 ION_IOC_CLEAN_INV_CACHES);
3254 if (ret) {
3255 pr_err("cache operation failed %d\n", ret);
3256 return ret;
3257 }
3258
3259 __qseecom_reentrancy_check_if_this_app_blocked(ptr_app);
3260
3261 ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1,
3262 cmd_buf, cmd_len,
3263 &resp, sizeof(resp));
3264 if (ret) {
3265 pr_err("scm_call() failed with err: %d (app_id = %d)\n",
3266 ret, data->client.app_id);
Zhen Kong4af480e2017-09-19 14:34:16 -07003267 goto exit;
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07003268 }
3269
3270 if (qseecom.qsee_reentrancy_support) {
3271 ret = __qseecom_process_reentrancy(&resp, ptr_app, data);
Zhen Kong4af480e2017-09-19 14:34:16 -07003272 if (ret)
3273 goto exit;
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07003274 } else {
3275 if (resp.result == QSEOS_RESULT_INCOMPLETE) {
3276 ret = __qseecom_process_incomplete_cmd(data, &resp);
3277 if (ret) {
3278 pr_err("process_incomplete_cmd failed err: %d\n",
3279 ret);
Zhen Kong4af480e2017-09-19 14:34:16 -07003280 goto exit;
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07003281 }
3282 } else {
3283 if (resp.result != QSEOS_RESULT_SUCCESS) {
3284 pr_err("Response result %d not supported\n",
3285 resp.result);
3286 ret = -EINVAL;
Zhen Kong4af480e2017-09-19 14:34:16 -07003287 goto exit;
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07003288 }
3289 }
3290 }
Zhen Kong4af480e2017-09-19 14:34:16 -07003291exit:
3292 ret2 = msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07003293 data->client.sb_virt, data->client.sb_length,
3294 ION_IOC_INV_CACHES);
Zhen Kong4af480e2017-09-19 14:34:16 -07003295 if (ret2) {
3296 pr_err("cache operation failed %d\n", ret2);
3297 return ret2;
3298 }
Zhen Kongbcdeda22018-11-16 13:50:51 -08003299 __qseecom_processing_pending_lsnr_unregister();
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07003300 return ret;
3301}
3302
3303static int qseecom_send_cmd(struct qseecom_dev_handle *data, void __user *argp)
3304{
3305 int ret = 0;
3306 struct qseecom_send_cmd_req req;
3307
3308 ret = copy_from_user(&req, argp, sizeof(req));
3309 if (ret) {
3310 pr_err("copy_from_user failed\n");
3311 return ret;
3312 }
3313
3314 if (__validate_send_cmd_inputs(data, &req))
3315 return -EINVAL;
3316
3317 ret = __qseecom_send_cmd(data, &req);
3318
3319 if (ret)
3320 return ret;
3321
3322 return ret;
3323}
3324
3325int __boundary_checks_offset(struct qseecom_send_modfd_cmd_req *req,
3326 struct qseecom_send_modfd_listener_resp *lstnr_resp,
3327 struct qseecom_dev_handle *data, int i) {
3328
3329 if ((data->type != QSEECOM_LISTENER_SERVICE) &&
3330 (req->ifd_data[i].fd > 0)) {
3331 if ((req->cmd_req_len < sizeof(uint32_t)) ||
3332 (req->ifd_data[i].cmd_buf_offset >
3333 req->cmd_req_len - sizeof(uint32_t))) {
3334 pr_err("Invalid offset (req len) 0x%x\n",
3335 req->ifd_data[i].cmd_buf_offset);
3336 return -EINVAL;
3337 }
3338 } else if ((data->type == QSEECOM_LISTENER_SERVICE) &&
3339 (lstnr_resp->ifd_data[i].fd > 0)) {
3340 if ((lstnr_resp->resp_len < sizeof(uint32_t)) ||
3341 (lstnr_resp->ifd_data[i].cmd_buf_offset >
3342 lstnr_resp->resp_len - sizeof(uint32_t))) {
3343 pr_err("Invalid offset (lstnr resp len) 0x%x\n",
3344 lstnr_resp->ifd_data[i].cmd_buf_offset);
3345 return -EINVAL;
3346 }
3347 }
3348 return 0;
3349}
3350
3351static int __qseecom_update_cmd_buf(void *msg, bool cleanup,
3352 struct qseecom_dev_handle *data)
3353{
3354 struct ion_handle *ihandle;
3355 char *field;
3356 int ret = 0;
3357 int i = 0;
3358 uint32_t len = 0;
3359 struct scatterlist *sg;
3360 struct qseecom_send_modfd_cmd_req *req = NULL;
3361 struct qseecom_send_modfd_listener_resp *lstnr_resp = NULL;
3362 struct qseecom_registered_listener_list *this_lstnr = NULL;
3363 uint32_t offset;
3364 struct sg_table *sg_ptr;
3365
3366 if ((data->type != QSEECOM_LISTENER_SERVICE) &&
3367 (data->type != QSEECOM_CLIENT_APP))
3368 return -EFAULT;
3369
3370 if (msg == NULL) {
3371 pr_err("Invalid address\n");
3372 return -EINVAL;
3373 }
3374 if (data->type == QSEECOM_LISTENER_SERVICE) {
3375 lstnr_resp = (struct qseecom_send_modfd_listener_resp *)msg;
3376 this_lstnr = __qseecom_find_svc(data->listener.id);
3377 if (IS_ERR_OR_NULL(this_lstnr)) {
3378 pr_err("Invalid listener ID\n");
3379 return -ENOMEM;
3380 }
3381 } else {
3382 req = (struct qseecom_send_modfd_cmd_req *)msg;
3383 }
3384
3385 for (i = 0; i < MAX_ION_FD; i++) {
3386 if ((data->type != QSEECOM_LISTENER_SERVICE) &&
3387 (req->ifd_data[i].fd > 0)) {
AnilKumar Chimata04d60cf2017-04-09 11:43:10 -07003388 ihandle = ion_import_dma_buf_fd(qseecom.ion_clnt,
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07003389 req->ifd_data[i].fd);
3390 if (IS_ERR_OR_NULL(ihandle)) {
3391 pr_err("Ion client can't retrieve the handle\n");
3392 return -ENOMEM;
3393 }
3394 field = (char *) req->cmd_req_buf +
3395 req->ifd_data[i].cmd_buf_offset;
3396 } else if ((data->type == QSEECOM_LISTENER_SERVICE) &&
3397 (lstnr_resp->ifd_data[i].fd > 0)) {
AnilKumar Chimata04d60cf2017-04-09 11:43:10 -07003398 ihandle = ion_import_dma_buf_fd(qseecom.ion_clnt,
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07003399 lstnr_resp->ifd_data[i].fd);
3400 if (IS_ERR_OR_NULL(ihandle)) {
3401 pr_err("Ion client can't retrieve the handle\n");
3402 return -ENOMEM;
3403 }
3404 field = lstnr_resp->resp_buf_ptr +
3405 lstnr_resp->ifd_data[i].cmd_buf_offset;
3406 } else {
3407 continue;
3408 }
3409 /* Populate the cmd data structure with the phys_addr */
3410 sg_ptr = ion_sg_table(qseecom.ion_clnt, ihandle);
3411 if (IS_ERR_OR_NULL(sg_ptr)) {
3412 pr_err("IOn client could not retrieve sg table\n");
3413 goto err;
3414 }
3415 if (sg_ptr->nents == 0) {
3416 pr_err("Num of scattered entries is 0\n");
3417 goto err;
3418 }
3419 if (sg_ptr->nents > QSEECOM_MAX_SG_ENTRY) {
3420 pr_err("Num of scattered entries");
3421 pr_err(" (%d) is greater than max supported %d\n",
3422 sg_ptr->nents, QSEECOM_MAX_SG_ENTRY);
3423 goto err;
3424 }
3425 sg = sg_ptr->sgl;
3426 if (sg_ptr->nents == 1) {
3427 uint32_t *update;
3428
3429 if (__boundary_checks_offset(req, lstnr_resp, data, i))
3430 goto err;
3431 if ((data->type == QSEECOM_CLIENT_APP &&
3432 (data->client.app_arch == ELFCLASS32 ||
3433 data->client.app_arch == ELFCLASS64)) ||
3434 (data->type == QSEECOM_LISTENER_SERVICE)) {
3435 /*
3436 * Check if sg list phy add region is under 4GB
3437 */
3438 if ((qseecom.qsee_version >= QSEE_VERSION_40) &&
3439 (!cleanup) &&
3440 ((uint64_t)sg_dma_address(sg_ptr->sgl)
3441 >= PHY_ADDR_4G - sg->length)) {
3442 pr_err("App %s sgl PA exceeds 4G: phy_addr=%pKad, len=%x\n",
3443 data->client.app_name,
3444 &(sg_dma_address(sg_ptr->sgl)),
3445 sg->length);
3446 goto err;
3447 }
3448 update = (uint32_t *) field;
3449 *update = cleanup ? 0 :
3450 (uint32_t)sg_dma_address(sg_ptr->sgl);
3451 } else {
3452 pr_err("QSEE app arch %u is not supported\n",
3453 data->client.app_arch);
3454 goto err;
3455 }
3456 len += (uint32_t)sg->length;
3457 } else {
3458 struct qseecom_sg_entry *update;
3459 int j = 0;
3460
3461 if ((data->type != QSEECOM_LISTENER_SERVICE) &&
3462 (req->ifd_data[i].fd > 0)) {
3463
3464 if ((req->cmd_req_len <
3465 SG_ENTRY_SZ * sg_ptr->nents) ||
3466 (req->ifd_data[i].cmd_buf_offset >
3467 (req->cmd_req_len -
3468 SG_ENTRY_SZ * sg_ptr->nents))) {
3469 pr_err("Invalid offset = 0x%x\n",
3470 req->ifd_data[i].cmd_buf_offset);
3471 goto err;
3472 }
3473
3474 } else if ((data->type == QSEECOM_LISTENER_SERVICE) &&
3475 (lstnr_resp->ifd_data[i].fd > 0)) {
3476
3477 if ((lstnr_resp->resp_len <
3478 SG_ENTRY_SZ * sg_ptr->nents) ||
3479 (lstnr_resp->ifd_data[i].cmd_buf_offset >
3480 (lstnr_resp->resp_len -
3481 SG_ENTRY_SZ * sg_ptr->nents))) {
3482 goto err;
3483 }
3484 }
3485 if ((data->type == QSEECOM_CLIENT_APP &&
3486 (data->client.app_arch == ELFCLASS32 ||
3487 data->client.app_arch == ELFCLASS64)) ||
3488 (data->type == QSEECOM_LISTENER_SERVICE)) {
3489 update = (struct qseecom_sg_entry *)field;
3490 for (j = 0; j < sg_ptr->nents; j++) {
3491 /*
3492 * Check if sg list PA is under 4GB
3493 */
3494 if ((qseecom.qsee_version >=
3495 QSEE_VERSION_40) &&
3496 (!cleanup) &&
3497 ((uint64_t)(sg_dma_address(sg))
3498 >= PHY_ADDR_4G - sg->length)) {
3499 pr_err("App %s sgl PA exceeds 4G: phy_addr=%pKad, len=%x\n",
3500 data->client.app_name,
3501 &(sg_dma_address(sg)),
3502 sg->length);
3503 goto err;
3504 }
3505 update->phys_addr = cleanup ? 0 :
3506 (uint32_t)sg_dma_address(sg);
3507 update->len = cleanup ? 0 : sg->length;
3508 update++;
3509 len += sg->length;
3510 sg = sg_next(sg);
3511 }
3512 } else {
3513 pr_err("QSEE app arch %u is not supported\n",
3514 data->client.app_arch);
3515 goto err;
3516 }
3517 }
3518
3519 if (cleanup) {
3520 ret = msm_ion_do_cache_op(qseecom.ion_clnt,
3521 ihandle, NULL, len,
3522 ION_IOC_INV_CACHES);
3523 if (ret) {
3524 pr_err("cache operation failed %d\n", ret);
3525 goto err;
3526 }
3527 } else {
3528 ret = msm_ion_do_cache_op(qseecom.ion_clnt,
3529 ihandle, NULL, len,
3530 ION_IOC_CLEAN_INV_CACHES);
3531 if (ret) {
3532 pr_err("cache operation failed %d\n", ret);
3533 goto err;
3534 }
3535 if (data->type == QSEECOM_CLIENT_APP) {
3536 offset = req->ifd_data[i].cmd_buf_offset;
3537 data->sglistinfo_ptr[i].indexAndFlags =
3538 SGLISTINFO_SET_INDEX_FLAG(
3539 (sg_ptr->nents == 1), 0, offset);
3540 data->sglistinfo_ptr[i].sizeOrCount =
3541 (sg_ptr->nents == 1) ?
3542 sg->length : sg_ptr->nents;
3543 data->sglist_cnt = i + 1;
3544 } else {
3545 offset = (lstnr_resp->ifd_data[i].cmd_buf_offset
3546 + (uintptr_t)lstnr_resp->resp_buf_ptr -
3547 (uintptr_t)this_lstnr->sb_virt);
3548 this_lstnr->sglistinfo_ptr[i].indexAndFlags =
3549 SGLISTINFO_SET_INDEX_FLAG(
3550 (sg_ptr->nents == 1), 0, offset);
3551 this_lstnr->sglistinfo_ptr[i].sizeOrCount =
3552 (sg_ptr->nents == 1) ?
3553 sg->length : sg_ptr->nents;
3554 this_lstnr->sglist_cnt = i + 1;
3555 }
3556 }
3557 /* Deallocate the handle */
3558 if (!IS_ERR_OR_NULL(ihandle))
3559 ion_free(qseecom.ion_clnt, ihandle);
3560 }
3561 return ret;
3562err:
3563 if (!IS_ERR_OR_NULL(ihandle))
3564 ion_free(qseecom.ion_clnt, ihandle);
3565 return -ENOMEM;
3566}
3567
3568static int __qseecom_allocate_sg_list_buffer(struct qseecom_dev_handle *data,
3569 char *field, uint32_t fd_idx, struct sg_table *sg_ptr)
3570{
3571 struct scatterlist *sg = sg_ptr->sgl;
3572 struct qseecom_sg_entry_64bit *sg_entry;
3573 struct qseecom_sg_list_buf_hdr_64bit *buf_hdr;
3574 void *buf;
3575 uint i;
3576 size_t size;
3577 dma_addr_t coh_pmem;
3578
3579 if (fd_idx >= MAX_ION_FD) {
3580 pr_err("fd_idx [%d] is invalid\n", fd_idx);
3581 return -ENOMEM;
3582 }
3583 buf_hdr = (struct qseecom_sg_list_buf_hdr_64bit *)field;
3584 memset((void *)buf_hdr, 0, QSEECOM_SG_LIST_BUF_HDR_SZ_64BIT);
3585 /* Allocate a contiguous kernel buffer */
3586 size = sg_ptr->nents * SG_ENTRY_SZ_64BIT;
3587 size = (size + PAGE_SIZE) & PAGE_MASK;
3588 buf = dma_alloc_coherent(qseecom.pdev,
3589 size, &coh_pmem, GFP_KERNEL);
3590 if (buf == NULL) {
3591 pr_err("failed to alloc memory for sg buf\n");
3592 return -ENOMEM;
3593 }
3594 /* update qseecom_sg_list_buf_hdr_64bit */
3595 buf_hdr->version = QSEECOM_SG_LIST_BUF_FORMAT_VERSION_2;
3596 buf_hdr->new_buf_phys_addr = coh_pmem;
3597 buf_hdr->nents_total = sg_ptr->nents;
3598 /* save the left sg entries into new allocated buf */
3599 sg_entry = (struct qseecom_sg_entry_64bit *)buf;
3600 for (i = 0; i < sg_ptr->nents; i++) {
3601 sg_entry->phys_addr = (uint64_t)sg_dma_address(sg);
3602 sg_entry->len = sg->length;
3603 sg_entry++;
3604 sg = sg_next(sg);
3605 }
3606
3607 data->client.sec_buf_fd[fd_idx].is_sec_buf_fd = true;
3608 data->client.sec_buf_fd[fd_idx].vbase = buf;
3609 data->client.sec_buf_fd[fd_idx].pbase = coh_pmem;
3610 data->client.sec_buf_fd[fd_idx].size = size;
3611
3612 return 0;
3613}
3614
3615static int __qseecom_update_cmd_buf_64(void *msg, bool cleanup,
3616 struct qseecom_dev_handle *data)
3617{
3618 struct ion_handle *ihandle;
3619 char *field;
3620 int ret = 0;
3621 int i = 0;
3622 uint32_t len = 0;
3623 struct scatterlist *sg;
3624 struct qseecom_send_modfd_cmd_req *req = NULL;
3625 struct qseecom_send_modfd_listener_resp *lstnr_resp = NULL;
3626 struct qseecom_registered_listener_list *this_lstnr = NULL;
3627 uint32_t offset;
3628 struct sg_table *sg_ptr;
3629
3630 if ((data->type != QSEECOM_LISTENER_SERVICE) &&
3631 (data->type != QSEECOM_CLIENT_APP))
3632 return -EFAULT;
3633
3634 if (msg == NULL) {
3635 pr_err("Invalid address\n");
3636 return -EINVAL;
3637 }
3638 if (data->type == QSEECOM_LISTENER_SERVICE) {
3639 lstnr_resp = (struct qseecom_send_modfd_listener_resp *)msg;
3640 this_lstnr = __qseecom_find_svc(data->listener.id);
3641 if (IS_ERR_OR_NULL(this_lstnr)) {
3642 pr_err("Invalid listener ID\n");
3643 return -ENOMEM;
3644 }
3645 } else {
3646 req = (struct qseecom_send_modfd_cmd_req *)msg;
3647 }
3648
3649 for (i = 0; i < MAX_ION_FD; i++) {
3650 if ((data->type != QSEECOM_LISTENER_SERVICE) &&
3651 (req->ifd_data[i].fd > 0)) {
AnilKumar Chimata04d60cf2017-04-09 11:43:10 -07003652 ihandle = ion_import_dma_buf_fd(qseecom.ion_clnt,
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07003653 req->ifd_data[i].fd);
3654 if (IS_ERR_OR_NULL(ihandle)) {
3655 pr_err("Ion client can't retrieve the handle\n");
3656 return -ENOMEM;
3657 }
3658 field = (char *) req->cmd_req_buf +
3659 req->ifd_data[i].cmd_buf_offset;
3660 } else if ((data->type == QSEECOM_LISTENER_SERVICE) &&
3661 (lstnr_resp->ifd_data[i].fd > 0)) {
AnilKumar Chimata04d60cf2017-04-09 11:43:10 -07003662 ihandle = ion_import_dma_buf_fd(qseecom.ion_clnt,
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07003663 lstnr_resp->ifd_data[i].fd);
3664 if (IS_ERR_OR_NULL(ihandle)) {
3665 pr_err("Ion client can't retrieve the handle\n");
3666 return -ENOMEM;
3667 }
3668 field = lstnr_resp->resp_buf_ptr +
3669 lstnr_resp->ifd_data[i].cmd_buf_offset;
3670 } else {
3671 continue;
3672 }
3673 /* Populate the cmd data structure with the phys_addr */
3674 sg_ptr = ion_sg_table(qseecom.ion_clnt, ihandle);
3675 if (IS_ERR_OR_NULL(sg_ptr)) {
3676 pr_err("IOn client could not retrieve sg table\n");
3677 goto err;
3678 }
3679 if (sg_ptr->nents == 0) {
3680 pr_err("Num of scattered entries is 0\n");
3681 goto err;
3682 }
3683 if (sg_ptr->nents > QSEECOM_MAX_SG_ENTRY) {
3684 pr_warn("Num of scattered entries");
3685 pr_warn(" (%d) is greater than %d\n",
3686 sg_ptr->nents, QSEECOM_MAX_SG_ENTRY);
3687 if (cleanup) {
3688 if (data->client.sec_buf_fd[i].is_sec_buf_fd &&
3689 data->client.sec_buf_fd[i].vbase)
3690 dma_free_coherent(qseecom.pdev,
3691 data->client.sec_buf_fd[i].size,
3692 data->client.sec_buf_fd[i].vbase,
3693 data->client.sec_buf_fd[i].pbase);
3694 } else {
3695 ret = __qseecom_allocate_sg_list_buffer(data,
3696 field, i, sg_ptr);
3697 if (ret) {
3698 pr_err("Failed to allocate sg list buffer\n");
3699 goto err;
3700 }
3701 }
3702 len = QSEECOM_SG_LIST_BUF_HDR_SZ_64BIT;
3703 sg = sg_ptr->sgl;
3704 goto cleanup;
3705 }
3706 sg = sg_ptr->sgl;
3707 if (sg_ptr->nents == 1) {
3708 uint64_t *update_64bit;
3709
3710 if (__boundary_checks_offset(req, lstnr_resp, data, i))
3711 goto err;
3712 /* 64bit app uses 64bit address */
3713 update_64bit = (uint64_t *) field;
3714 *update_64bit = cleanup ? 0 :
3715 (uint64_t)sg_dma_address(sg_ptr->sgl);
3716 len += (uint32_t)sg->length;
3717 } else {
3718 struct qseecom_sg_entry_64bit *update_64bit;
3719 int j = 0;
3720
3721 if ((data->type != QSEECOM_LISTENER_SERVICE) &&
3722 (req->ifd_data[i].fd > 0)) {
3723
3724 if ((req->cmd_req_len <
3725 SG_ENTRY_SZ_64BIT * sg_ptr->nents) ||
3726 (req->ifd_data[i].cmd_buf_offset >
3727 (req->cmd_req_len -
3728 SG_ENTRY_SZ_64BIT * sg_ptr->nents))) {
3729 pr_err("Invalid offset = 0x%x\n",
3730 req->ifd_data[i].cmd_buf_offset);
3731 goto err;
3732 }
3733
3734 } else if ((data->type == QSEECOM_LISTENER_SERVICE) &&
3735 (lstnr_resp->ifd_data[i].fd > 0)) {
3736
3737 if ((lstnr_resp->resp_len <
3738 SG_ENTRY_SZ_64BIT * sg_ptr->nents) ||
3739 (lstnr_resp->ifd_data[i].cmd_buf_offset >
3740 (lstnr_resp->resp_len -
3741 SG_ENTRY_SZ_64BIT * sg_ptr->nents))) {
3742 goto err;
3743 }
3744 }
3745 /* 64bit app uses 64bit address */
3746 update_64bit = (struct qseecom_sg_entry_64bit *)field;
3747 for (j = 0; j < sg_ptr->nents; j++) {
3748 update_64bit->phys_addr = cleanup ? 0 :
3749 (uint64_t)sg_dma_address(sg);
3750 update_64bit->len = cleanup ? 0 :
3751 (uint32_t)sg->length;
3752 update_64bit++;
3753 len += sg->length;
3754 sg = sg_next(sg);
3755 }
3756 }
3757cleanup:
3758 if (cleanup) {
3759 ret = msm_ion_do_cache_op(qseecom.ion_clnt,
3760 ihandle, NULL, len,
3761 ION_IOC_INV_CACHES);
3762 if (ret) {
3763 pr_err("cache operation failed %d\n", ret);
3764 goto err;
3765 }
3766 } else {
3767 ret = msm_ion_do_cache_op(qseecom.ion_clnt,
3768 ihandle, NULL, len,
3769 ION_IOC_CLEAN_INV_CACHES);
3770 if (ret) {
3771 pr_err("cache operation failed %d\n", ret);
3772 goto err;
3773 }
3774 if (data->type == QSEECOM_CLIENT_APP) {
3775 offset = req->ifd_data[i].cmd_buf_offset;
3776 data->sglistinfo_ptr[i].indexAndFlags =
3777 SGLISTINFO_SET_INDEX_FLAG(
3778 (sg_ptr->nents == 1), 1, offset);
3779 data->sglistinfo_ptr[i].sizeOrCount =
3780 (sg_ptr->nents == 1) ?
3781 sg->length : sg_ptr->nents;
3782 data->sglist_cnt = i + 1;
3783 } else {
3784 offset = (lstnr_resp->ifd_data[i].cmd_buf_offset
3785 + (uintptr_t)lstnr_resp->resp_buf_ptr -
3786 (uintptr_t)this_lstnr->sb_virt);
3787 this_lstnr->sglistinfo_ptr[i].indexAndFlags =
3788 SGLISTINFO_SET_INDEX_FLAG(
3789 (sg_ptr->nents == 1), 1, offset);
3790 this_lstnr->sglistinfo_ptr[i].sizeOrCount =
3791 (sg_ptr->nents == 1) ?
3792 sg->length : sg_ptr->nents;
3793 this_lstnr->sglist_cnt = i + 1;
3794 }
3795 }
3796 /* Deallocate the handle */
3797 if (!IS_ERR_OR_NULL(ihandle))
3798 ion_free(qseecom.ion_clnt, ihandle);
3799 }
3800 return ret;
3801err:
3802 for (i = 0; i < MAX_ION_FD; i++)
3803 if (data->client.sec_buf_fd[i].is_sec_buf_fd &&
3804 data->client.sec_buf_fd[i].vbase)
3805 dma_free_coherent(qseecom.pdev,
3806 data->client.sec_buf_fd[i].size,
3807 data->client.sec_buf_fd[i].vbase,
3808 data->client.sec_buf_fd[i].pbase);
3809 if (!IS_ERR_OR_NULL(ihandle))
3810 ion_free(qseecom.ion_clnt, ihandle);
3811 return -ENOMEM;
3812}
3813
3814static int __qseecom_send_modfd_cmd(struct qseecom_dev_handle *data,
3815 void __user *argp,
3816 bool is_64bit_addr)
3817{
3818 int ret = 0;
3819 int i;
3820 struct qseecom_send_modfd_cmd_req req;
3821 struct qseecom_send_cmd_req send_cmd_req;
3822
3823 ret = copy_from_user(&req, argp, sizeof(req));
3824 if (ret) {
3825 pr_err("copy_from_user failed\n");
3826 return ret;
3827 }
3828
3829 send_cmd_req.cmd_req_buf = req.cmd_req_buf;
3830 send_cmd_req.cmd_req_len = req.cmd_req_len;
3831 send_cmd_req.resp_buf = req.resp_buf;
3832 send_cmd_req.resp_len = req.resp_len;
3833
3834 if (__validate_send_cmd_inputs(data, &send_cmd_req))
3835 return -EINVAL;
3836
3837 /* validate offsets */
3838 for (i = 0; i < MAX_ION_FD; i++) {
3839 if (req.ifd_data[i].cmd_buf_offset >= req.cmd_req_len) {
3840 pr_err("Invalid offset %d = 0x%x\n",
3841 i, req.ifd_data[i].cmd_buf_offset);
3842 return -EINVAL;
3843 }
3844 }
3845 req.cmd_req_buf = (void *)__qseecom_uvirt_to_kvirt(data,
3846 (uintptr_t)req.cmd_req_buf);
3847 req.resp_buf = (void *)__qseecom_uvirt_to_kvirt(data,
3848 (uintptr_t)req.resp_buf);
3849
3850 if (!is_64bit_addr) {
3851 ret = __qseecom_update_cmd_buf(&req, false, data);
3852 if (ret)
3853 return ret;
3854 ret = __qseecom_send_cmd(data, &send_cmd_req);
3855 if (ret)
3856 return ret;
3857 ret = __qseecom_update_cmd_buf(&req, true, data);
3858 if (ret)
3859 return ret;
3860 } else {
3861 ret = __qseecom_update_cmd_buf_64(&req, false, data);
3862 if (ret)
3863 return ret;
3864 ret = __qseecom_send_cmd(data, &send_cmd_req);
3865 if (ret)
3866 return ret;
3867 ret = __qseecom_update_cmd_buf_64(&req, true, data);
3868 if (ret)
3869 return ret;
3870 }
3871
3872 return ret;
3873}
3874
3875static int qseecom_send_modfd_cmd(struct qseecom_dev_handle *data,
3876 void __user *argp)
3877{
3878 return __qseecom_send_modfd_cmd(data, argp, false);
3879}
3880
3881static int qseecom_send_modfd_cmd_64(struct qseecom_dev_handle *data,
3882 void __user *argp)
3883{
3884 return __qseecom_send_modfd_cmd(data, argp, true);
3885}
3886
3887
3888
3889static int __qseecom_listener_has_rcvd_req(struct qseecom_dev_handle *data,
3890 struct qseecom_registered_listener_list *svc)
3891{
3892 int ret;
3893
Zhen Kongf5087172018-10-11 17:22:05 -07003894 ret = (svc->rcv_req_flag == 1);
Zhen Kongbcdeda22018-11-16 13:50:51 -08003895 return ret || data->abort;
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07003896}
3897
3898static int qseecom_receive_req(struct qseecom_dev_handle *data)
3899{
3900 int ret = 0;
3901 struct qseecom_registered_listener_list *this_lstnr;
3902
Zhen Kongbcdeda22018-11-16 13:50:51 -08003903 mutex_lock(&listener_access_lock);
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07003904 this_lstnr = __qseecom_find_svc(data->listener.id);
3905 if (!this_lstnr) {
3906 pr_err("Invalid listener ID\n");
Zhen Kongbcdeda22018-11-16 13:50:51 -08003907 mutex_unlock(&listener_access_lock);
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07003908 return -ENODATA;
3909 }
Zhen Kongbcdeda22018-11-16 13:50:51 -08003910 mutex_unlock(&listener_access_lock);
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07003911
3912 while (1) {
3913 if (wait_event_freezable(this_lstnr->rcv_req_wq,
3914 __qseecom_listener_has_rcvd_req(data,
3915 this_lstnr))) {
Zhen Kong25731112018-09-20 13:10:03 -07003916 pr_warn("Interrupted: exiting Listener Service = %d\n",
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07003917 (uint32_t)data->listener.id);
3918 /* woken up for different reason */
3919 return -ERESTARTSYS;
3920 }
3921
Zhen Kongbcdeda22018-11-16 13:50:51 -08003922 if (data->abort) {
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07003923 pr_err("Aborting Listener Service = %d\n",
Zhen Kong26e62742018-05-04 17:19:06 -07003924 (uint32_t)data->listener.id);
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07003925 return -ENODEV;
3926 }
Zhen Kongbcdeda22018-11-16 13:50:51 -08003927 mutex_lock(&listener_access_lock);
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07003928 this_lstnr->rcv_req_flag = 0;
Zhen Kongbcdeda22018-11-16 13:50:51 -08003929 mutex_unlock(&listener_access_lock);
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07003930 break;
3931 }
3932 return ret;
3933}
3934
3935static bool __qseecom_is_fw_image_valid(const struct firmware *fw_entry)
3936{
3937 unsigned char app_arch = 0;
3938 struct elf32_hdr *ehdr;
3939 struct elf64_hdr *ehdr64;
3940
3941 app_arch = *(unsigned char *)(fw_entry->data + EI_CLASS);
3942
3943 switch (app_arch) {
3944 case ELFCLASS32: {
3945 ehdr = (struct elf32_hdr *)fw_entry->data;
3946 if (fw_entry->size < sizeof(*ehdr)) {
3947 pr_err("%s: Not big enough to be an elf32 header\n",
3948 qseecom.pdev->init_name);
3949 return false;
3950 }
3951 if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
3952 pr_err("%s: Not an elf32 header\n",
3953 qseecom.pdev->init_name);
3954 return false;
3955 }
3956 if (ehdr->e_phnum == 0) {
3957 pr_err("%s: No loadable segments\n",
3958 qseecom.pdev->init_name);
3959 return false;
3960 }
3961 if (sizeof(struct elf32_phdr) * ehdr->e_phnum +
3962 sizeof(struct elf32_hdr) > fw_entry->size) {
3963 pr_err("%s: Program headers not within mdt\n",
3964 qseecom.pdev->init_name);
3965 return false;
3966 }
3967 break;
3968 }
3969 case ELFCLASS64: {
3970 ehdr64 = (struct elf64_hdr *)fw_entry->data;
3971 if (fw_entry->size < sizeof(*ehdr64)) {
3972 pr_err("%s: Not big enough to be an elf64 header\n",
3973 qseecom.pdev->init_name);
3974 return false;
3975 }
3976 if (memcmp(ehdr64->e_ident, ELFMAG, SELFMAG)) {
3977 pr_err("%s: Not an elf64 header\n",
3978 qseecom.pdev->init_name);
3979 return false;
3980 }
3981 if (ehdr64->e_phnum == 0) {
3982 pr_err("%s: No loadable segments\n",
3983 qseecom.pdev->init_name);
3984 return false;
3985 }
3986 if (sizeof(struct elf64_phdr) * ehdr64->e_phnum +
3987 sizeof(struct elf64_hdr) > fw_entry->size) {
3988 pr_err("%s: Program headers not within mdt\n",
3989 qseecom.pdev->init_name);
3990 return false;
3991 }
3992 break;
3993 }
3994 default: {
3995 pr_err("QSEE app arch %u is not supported\n", app_arch);
3996 return false;
3997 }
3998 }
3999 return true;
4000}
4001
4002static int __qseecom_get_fw_size(const char *appname, uint32_t *fw_size,
4003 uint32_t *app_arch)
4004{
4005 int ret = -1;
4006 int i = 0, rc = 0;
4007 const struct firmware *fw_entry = NULL;
4008 char fw_name[MAX_APP_NAME_SIZE];
4009 struct elf32_hdr *ehdr;
4010 struct elf64_hdr *ehdr64;
4011 int num_images = 0;
4012
4013 snprintf(fw_name, sizeof(fw_name), "%s.mdt", appname);
4014 rc = request_firmware(&fw_entry, fw_name, qseecom.pdev);
4015 if (rc) {
4016 pr_err("error with request_firmware\n");
4017 ret = -EIO;
4018 goto err;
4019 }
4020 if (!__qseecom_is_fw_image_valid(fw_entry)) {
4021 ret = -EIO;
4022 goto err;
4023 }
4024 *app_arch = *(unsigned char *)(fw_entry->data + EI_CLASS);
4025 *fw_size = fw_entry->size;
4026 if (*app_arch == ELFCLASS32) {
4027 ehdr = (struct elf32_hdr *)fw_entry->data;
4028 num_images = ehdr->e_phnum;
4029 } else if (*app_arch == ELFCLASS64) {
4030 ehdr64 = (struct elf64_hdr *)fw_entry->data;
4031 num_images = ehdr64->e_phnum;
4032 } else {
4033 pr_err("QSEE %s app, arch %u is not supported\n",
4034 appname, *app_arch);
4035 ret = -EIO;
4036 goto err;
4037 }
4038 pr_debug("QSEE %s app, arch %u\n", appname, *app_arch);
4039 release_firmware(fw_entry);
4040 fw_entry = NULL;
4041 for (i = 0; i < num_images; i++) {
4042 memset(fw_name, 0, sizeof(fw_name));
4043 snprintf(fw_name, ARRAY_SIZE(fw_name), "%s.b%02d", appname, i);
4044 ret = request_firmware(&fw_entry, fw_name, qseecom.pdev);
4045 if (ret)
4046 goto err;
4047 if (*fw_size > U32_MAX - fw_entry->size) {
4048 pr_err("QSEE %s app file size overflow\n", appname);
4049 ret = -EINVAL;
4050 goto err;
4051 }
4052 *fw_size += fw_entry->size;
4053 release_firmware(fw_entry);
4054 fw_entry = NULL;
4055 }
4056
4057 return ret;
4058err:
4059 if (fw_entry)
4060 release_firmware(fw_entry);
4061 *fw_size = 0;
4062 return ret;
4063}
4064
4065static int __qseecom_get_fw_data(const char *appname, u8 *img_data,
4066 uint32_t fw_size,
4067 struct qseecom_load_app_ireq *load_req)
4068{
4069 int ret = -1;
4070 int i = 0, rc = 0;
4071 const struct firmware *fw_entry = NULL;
4072 char fw_name[MAX_APP_NAME_SIZE];
4073 u8 *img_data_ptr = img_data;
4074 struct elf32_hdr *ehdr;
4075 struct elf64_hdr *ehdr64;
4076 int num_images = 0;
4077 unsigned char app_arch = 0;
4078
4079 snprintf(fw_name, sizeof(fw_name), "%s.mdt", appname);
4080 rc = request_firmware(&fw_entry, fw_name, qseecom.pdev);
4081 if (rc) {
4082 ret = -EIO;
4083 goto err;
4084 }
4085
4086 load_req->img_len = fw_entry->size;
4087 if (load_req->img_len > fw_size) {
4088 pr_err("app %s size %zu is larger than buf size %u\n",
4089 appname, fw_entry->size, fw_size);
4090 ret = -EINVAL;
4091 goto err;
4092 }
4093 memcpy(img_data_ptr, fw_entry->data, fw_entry->size);
4094 img_data_ptr = img_data_ptr + fw_entry->size;
4095 load_req->mdt_len = fw_entry->size; /*Get MDT LEN*/
4096
4097 app_arch = *(unsigned char *)(fw_entry->data + EI_CLASS);
4098 if (app_arch == ELFCLASS32) {
4099 ehdr = (struct elf32_hdr *)fw_entry->data;
4100 num_images = ehdr->e_phnum;
4101 } else if (app_arch == ELFCLASS64) {
4102 ehdr64 = (struct elf64_hdr *)fw_entry->data;
4103 num_images = ehdr64->e_phnum;
4104 } else {
4105 pr_err("QSEE %s app, arch %u is not supported\n",
4106 appname, app_arch);
4107 ret = -EIO;
4108 goto err;
4109 }
4110 release_firmware(fw_entry);
4111 fw_entry = NULL;
4112 for (i = 0; i < num_images; i++) {
4113 snprintf(fw_name, ARRAY_SIZE(fw_name), "%s.b%02d", appname, i);
4114 ret = request_firmware(&fw_entry, fw_name, qseecom.pdev);
4115 if (ret) {
4116 pr_err("Failed to locate blob %s\n", fw_name);
4117 goto err;
4118 }
4119 if ((fw_entry->size > U32_MAX - load_req->img_len) ||
4120 (fw_entry->size + load_req->img_len > fw_size)) {
4121 pr_err("Invalid file size for %s\n", fw_name);
4122 ret = -EINVAL;
4123 goto err;
4124 }
4125 memcpy(img_data_ptr, fw_entry->data, fw_entry->size);
4126 img_data_ptr = img_data_ptr + fw_entry->size;
4127 load_req->img_len += fw_entry->size;
4128 release_firmware(fw_entry);
4129 fw_entry = NULL;
4130 }
4131 return ret;
4132err:
4133 release_firmware(fw_entry);
4134 return ret;
4135}
4136
4137static int __qseecom_allocate_img_data(struct ion_handle **pihandle,
4138 u8 **data, uint32_t fw_size, ion_phys_addr_t *paddr)
4139{
4140 size_t len = 0;
4141 int ret = 0;
4142 ion_phys_addr_t pa;
4143 struct ion_handle *ihandle = NULL;
4144 u8 *img_data = NULL;
Zhen Kong3dd92792017-12-08 09:47:15 -08004145 int retry = 0;
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07004146
Zhen Kong3dd92792017-12-08 09:47:15 -08004147 do {
Zhen Kong5d02be92018-05-29 16:17:29 -07004148 if (retry++) {
4149 mutex_unlock(&app_access_lock);
Zhen Kong3dd92792017-12-08 09:47:15 -08004150 msleep(QSEECOM_TA_ION_ALLOCATE_DELAY);
Zhen Kong5d02be92018-05-29 16:17:29 -07004151 mutex_lock(&app_access_lock);
4152 }
Zhen Kong3dd92792017-12-08 09:47:15 -08004153 ihandle = ion_alloc(qseecom.ion_clnt, fw_size,
4154 SZ_4K, ION_HEAP(ION_QSECOM_TA_HEAP_ID), 0);
4155 } while (IS_ERR_OR_NULL(ihandle) &&
4156 (retry <= QSEECOM_TA_ION_ALLOCATE_MAX_ATTEMP));
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07004157
4158 if (IS_ERR_OR_NULL(ihandle)) {
4159 pr_err("ION alloc failed\n");
4160 return -ENOMEM;
4161 }
4162 img_data = (u8 *)ion_map_kernel(qseecom.ion_clnt,
4163 ihandle);
4164
4165 if (IS_ERR_OR_NULL(img_data)) {
4166 pr_err("ION memory mapping for image loading failed\n");
4167 ret = -ENOMEM;
4168 goto exit_ion_free;
4169 }
4170 /* Get the physical address of the ION BUF */
4171 ret = ion_phys(qseecom.ion_clnt, ihandle, &pa, &len);
4172 if (ret) {
4173 pr_err("physical memory retrieval failure\n");
4174 ret = -EIO;
4175 goto exit_ion_unmap_kernel;
4176 }
4177
4178 *pihandle = ihandle;
4179 *data = img_data;
4180 *paddr = pa;
4181 return ret;
4182
4183exit_ion_unmap_kernel:
4184 ion_unmap_kernel(qseecom.ion_clnt, ihandle);
4185exit_ion_free:
4186 ion_free(qseecom.ion_clnt, ihandle);
4187 ihandle = NULL;
4188 return ret;
4189}
4190
4191static void __qseecom_free_img_data(struct ion_handle **ihandle)
4192{
4193 ion_unmap_kernel(qseecom.ion_clnt, *ihandle);
4194 ion_free(qseecom.ion_clnt, *ihandle);
4195 *ihandle = NULL;
4196}
4197
4198static int __qseecom_load_fw(struct qseecom_dev_handle *data, char *appname,
4199 uint32_t *app_id)
4200{
4201 int ret = -1;
4202 uint32_t fw_size = 0;
4203 struct qseecom_load_app_ireq load_req = {0, 0, 0, 0};
4204 struct qseecom_load_app_64bit_ireq load_req_64bit = {0, 0, 0, 0};
4205 struct qseecom_command_scm_resp resp;
4206 u8 *img_data = NULL;
4207 ion_phys_addr_t pa = 0;
4208 struct ion_handle *ihandle = NULL;
4209 void *cmd_buf = NULL;
4210 size_t cmd_len;
4211 uint32_t app_arch = 0;
4212
4213 if (!data || !appname || !app_id) {
4214 pr_err("Null pointer to data or appname or appid\n");
4215 return -EINVAL;
4216 }
4217 *app_id = 0;
4218 if (__qseecom_get_fw_size(appname, &fw_size, &app_arch))
4219 return -EIO;
4220 data->client.app_arch = app_arch;
4221
4222 /* Check and load cmnlib */
4223 if (qseecom.qsee_version > QSEEE_VERSION_00) {
4224 if (!qseecom.commonlib_loaded && app_arch == ELFCLASS32) {
4225 ret = qseecom_load_commonlib_image(data, "cmnlib");
4226 if (ret) {
4227 pr_err("failed to load cmnlib\n");
4228 return -EIO;
4229 }
4230 qseecom.commonlib_loaded = true;
4231 pr_debug("cmnlib is loaded\n");
4232 }
4233
4234 if (!qseecom.commonlib64_loaded && app_arch == ELFCLASS64) {
4235 ret = qseecom_load_commonlib_image(data, "cmnlib64");
4236 if (ret) {
4237 pr_err("failed to load cmnlib64\n");
4238 return -EIO;
4239 }
4240 qseecom.commonlib64_loaded = true;
4241 pr_debug("cmnlib64 is loaded\n");
4242 }
4243 }
4244
4245 ret = __qseecom_allocate_img_data(&ihandle, &img_data, fw_size, &pa);
4246 if (ret)
4247 return ret;
4248
4249 ret = __qseecom_get_fw_data(appname, img_data, fw_size, &load_req);
4250 if (ret) {
4251 ret = -EIO;
4252 goto exit_free_img_data;
4253 }
4254
4255 /* Populate the load_req parameters */
4256 if (qseecom.qsee_version < QSEE_VERSION_40) {
4257 load_req.qsee_cmd_id = QSEOS_APP_START_COMMAND;
4258 load_req.mdt_len = load_req.mdt_len;
4259 load_req.img_len = load_req.img_len;
4260 strlcpy(load_req.app_name, appname, MAX_APP_NAME_SIZE);
4261 load_req.phy_addr = (uint32_t)pa;
4262 cmd_buf = (void *)&load_req;
4263 cmd_len = sizeof(struct qseecom_load_app_ireq);
4264 } else {
4265 load_req_64bit.qsee_cmd_id = QSEOS_APP_START_COMMAND;
4266 load_req_64bit.mdt_len = load_req.mdt_len;
4267 load_req_64bit.img_len = load_req.img_len;
4268 strlcpy(load_req_64bit.app_name, appname, MAX_APP_NAME_SIZE);
4269 load_req_64bit.phy_addr = (uint64_t)pa;
4270 cmd_buf = (void *)&load_req_64bit;
4271 cmd_len = sizeof(struct qseecom_load_app_64bit_ireq);
4272 }
4273
4274 if (qseecom.support_bus_scaling) {
4275 mutex_lock(&qsee_bw_mutex);
4276 ret = __qseecom_register_bus_bandwidth_needs(data, MEDIUM);
4277 mutex_unlock(&qsee_bw_mutex);
4278 if (ret) {
4279 ret = -EIO;
4280 goto exit_free_img_data;
4281 }
4282 }
4283
4284 ret = __qseecom_enable_clk_scale_up(data);
4285 if (ret) {
4286 ret = -EIO;
4287 goto exit_unregister_bus_bw_need;
4288 }
4289
4290 ret = msm_ion_do_cache_op(qseecom.ion_clnt, ihandle,
4291 img_data, fw_size,
4292 ION_IOC_CLEAN_INV_CACHES);
4293 if (ret) {
4294 pr_err("cache operation failed %d\n", ret);
4295 goto exit_disable_clk_vote;
4296 }
4297
4298 /* SCM_CALL to load the image */
4299 ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, cmd_buf, cmd_len,
4300 &resp, sizeof(resp));
4301 if (ret) {
Zhen Kong5d02be92018-05-29 16:17:29 -07004302 pr_err("scm_call to load failed : ret %d, result %x\n",
4303 ret, resp.result);
4304 if (resp.result == QSEOS_RESULT_FAIL_APP_ALREADY_LOADED)
4305 ret = -EEXIST;
4306 else
4307 ret = -EIO;
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07004308 goto exit_disable_clk_vote;
4309 }
4310
4311 switch (resp.result) {
4312 case QSEOS_RESULT_SUCCESS:
4313 *app_id = resp.data;
4314 break;
4315 case QSEOS_RESULT_INCOMPLETE:
4316 ret = __qseecom_process_incomplete_cmd(data, &resp);
4317 if (ret)
4318 pr_err("process_incomplete_cmd FAILED\n");
4319 else
4320 *app_id = resp.data;
4321 break;
4322 case QSEOS_RESULT_FAILURE:
4323 pr_err("scm call failed with response QSEOS_RESULT FAILURE\n");
4324 break;
4325 default:
4326 pr_err("scm call return unknown response %d\n", resp.result);
4327 ret = -EINVAL;
4328 break;
4329 }
4330
4331exit_disable_clk_vote:
4332 __qseecom_disable_clk_scale_down(data);
4333
4334exit_unregister_bus_bw_need:
4335 if (qseecom.support_bus_scaling) {
4336 mutex_lock(&qsee_bw_mutex);
4337 qseecom_unregister_bus_bandwidth_needs(data);
4338 mutex_unlock(&qsee_bw_mutex);
4339 }
4340
4341exit_free_img_data:
4342 __qseecom_free_img_data(&ihandle);
4343 return ret;
4344}
4345
4346static int qseecom_load_commonlib_image(struct qseecom_dev_handle *data,
4347 char *cmnlib_name)
4348{
4349 int ret = 0;
4350 uint32_t fw_size = 0;
4351 struct qseecom_load_app_ireq load_req = {0, 0, 0, 0};
4352 struct qseecom_load_app_64bit_ireq load_req_64bit = {0, 0, 0, 0};
4353 struct qseecom_command_scm_resp resp;
4354 u8 *img_data = NULL;
4355 ion_phys_addr_t pa = 0;
4356 void *cmd_buf = NULL;
4357 size_t cmd_len;
4358 uint32_t app_arch = 0;
Zhen Kong3bafb312017-10-18 10:27:20 -07004359 struct ion_handle *cmnlib_ion_handle = NULL;
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07004360
4361 if (!cmnlib_name) {
4362 pr_err("cmnlib_name is NULL\n");
4363 return -EINVAL;
4364 }
4365 if (strlen(cmnlib_name) >= MAX_APP_NAME_SIZE) {
4366 pr_err("The cmnlib_name (%s) with length %zu is not valid\n",
4367 cmnlib_name, strlen(cmnlib_name));
4368 return -EINVAL;
4369 }
4370
4371 if (__qseecom_get_fw_size(cmnlib_name, &fw_size, &app_arch))
4372 return -EIO;
4373
Zhen Kong3bafb312017-10-18 10:27:20 -07004374 ret = __qseecom_allocate_img_data(&cmnlib_ion_handle,
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07004375 &img_data, fw_size, &pa);
4376 if (ret)
4377 return -EIO;
4378
4379 ret = __qseecom_get_fw_data(cmnlib_name, img_data, fw_size, &load_req);
4380 if (ret) {
4381 ret = -EIO;
4382 goto exit_free_img_data;
4383 }
4384 if (qseecom.qsee_version < QSEE_VERSION_40) {
4385 load_req.phy_addr = (uint32_t)pa;
4386 load_req.qsee_cmd_id = QSEOS_LOAD_SERV_IMAGE_COMMAND;
4387 cmd_buf = (void *)&load_req;
4388 cmd_len = sizeof(struct qseecom_load_lib_image_ireq);
4389 } else {
4390 load_req_64bit.phy_addr = (uint64_t)pa;
4391 load_req_64bit.qsee_cmd_id = QSEOS_LOAD_SERV_IMAGE_COMMAND;
4392 load_req_64bit.img_len = load_req.img_len;
4393 load_req_64bit.mdt_len = load_req.mdt_len;
4394 cmd_buf = (void *)&load_req_64bit;
4395 cmd_len = sizeof(struct qseecom_load_lib_image_64bit_ireq);
4396 }
4397
4398 if (qseecom.support_bus_scaling) {
4399 mutex_lock(&qsee_bw_mutex);
4400 ret = __qseecom_register_bus_bandwidth_needs(data, MEDIUM);
4401 mutex_unlock(&qsee_bw_mutex);
4402 if (ret) {
4403 ret = -EIO;
4404 goto exit_free_img_data;
4405 }
4406 }
4407
4408 /* Vote for the SFPB clock */
4409 ret = __qseecom_enable_clk_scale_up(data);
4410 if (ret) {
4411 ret = -EIO;
4412 goto exit_unregister_bus_bw_need;
4413 }
4414
Zhen Kong3bafb312017-10-18 10:27:20 -07004415 ret = msm_ion_do_cache_op(qseecom.ion_clnt, cmnlib_ion_handle,
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07004416 img_data, fw_size,
4417 ION_IOC_CLEAN_INV_CACHES);
4418 if (ret) {
4419 pr_err("cache operation failed %d\n", ret);
4420 goto exit_disable_clk_vote;
4421 }
4422
4423 /* SCM_CALL to load the image */
4424 ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, cmd_buf, cmd_len,
4425 &resp, sizeof(resp));
4426 if (ret) {
4427 pr_err("scm_call to load failed : ret %d\n", ret);
4428 ret = -EIO;
4429 goto exit_disable_clk_vote;
4430 }
4431
4432 switch (resp.result) {
4433 case QSEOS_RESULT_SUCCESS:
4434 break;
4435 case QSEOS_RESULT_FAILURE:
4436 pr_err("scm call failed w/response result%d\n", resp.result);
4437 ret = -EINVAL;
4438 goto exit_disable_clk_vote;
4439 case QSEOS_RESULT_INCOMPLETE:
4440 ret = __qseecom_process_incomplete_cmd(data, &resp);
4441 if (ret) {
4442 pr_err("process_incomplete_cmd failed err: %d\n", ret);
4443 goto exit_disable_clk_vote;
4444 }
4445 break;
4446 default:
4447 pr_err("scm call return unknown response %d\n", resp.result);
4448 ret = -EINVAL;
4449 goto exit_disable_clk_vote;
4450 }
4451
4452exit_disable_clk_vote:
4453 __qseecom_disable_clk_scale_down(data);
4454
4455exit_unregister_bus_bw_need:
4456 if (qseecom.support_bus_scaling) {
4457 mutex_lock(&qsee_bw_mutex);
4458 qseecom_unregister_bus_bandwidth_needs(data);
4459 mutex_unlock(&qsee_bw_mutex);
4460 }
4461
4462exit_free_img_data:
Zhen Kong3bafb312017-10-18 10:27:20 -07004463 __qseecom_free_img_data(&cmnlib_ion_handle);
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07004464 return ret;
4465}
4466
4467static int qseecom_unload_commonlib_image(void)
4468{
4469 int ret = -EINVAL;
4470 struct qseecom_unload_lib_image_ireq unload_req = {0};
4471 struct qseecom_command_scm_resp resp;
4472
4473 /* Populate the remaining parameters */
4474 unload_req.qsee_cmd_id = QSEOS_UNLOAD_SERV_IMAGE_COMMAND;
4475
4476 /* SCM_CALL to load the image */
4477 ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, &unload_req,
4478 sizeof(struct qseecom_unload_lib_image_ireq),
4479 &resp, sizeof(resp));
4480 if (ret) {
4481 pr_err("scm_call to unload lib failed : ret %d\n", ret);
4482 ret = -EIO;
4483 } else {
4484 switch (resp.result) {
4485 case QSEOS_RESULT_SUCCESS:
4486 break;
4487 case QSEOS_RESULT_FAILURE:
4488 pr_err("scm fail resp.result QSEOS_RESULT FAILURE\n");
4489 break;
4490 default:
4491 pr_err("scm call return unknown response %d\n",
4492 resp.result);
4493 ret = -EINVAL;
4494 break;
4495 }
4496 }
4497
4498 return ret;
4499}
4500
4501int qseecom_start_app(struct qseecom_handle **handle,
4502 char *app_name, uint32_t size)
4503{
4504 int32_t ret = 0;
4505 unsigned long flags = 0;
4506 struct qseecom_dev_handle *data = NULL;
4507 struct qseecom_check_app_ireq app_ireq;
4508 struct qseecom_registered_app_list *entry = NULL;
4509 struct qseecom_registered_kclient_list *kclient_entry = NULL;
4510 bool found_app = false;
4511 size_t len;
4512 ion_phys_addr_t pa;
4513 uint32_t fw_size, app_arch;
4514 uint32_t app_id = 0;
4515
Zhen Kongbcdeda22018-11-16 13:50:51 -08004516 __qseecom_processing_pending_lsnr_unregister();
4517
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07004518 if (atomic_read(&qseecom.qseecom_state) != QSEECOM_STATE_READY) {
4519 pr_err("Not allowed to be called in %d state\n",
4520 atomic_read(&qseecom.qseecom_state));
4521 return -EPERM;
4522 }
4523 if (!app_name) {
4524 pr_err("failed to get the app name\n");
4525 return -EINVAL;
4526 }
4527
Zhen Kong64a6d7282017-06-16 11:55:07 -07004528 if (strnlen(app_name, MAX_APP_NAME_SIZE) == MAX_APP_NAME_SIZE) {
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07004529 pr_err("The app_name (%s) with length %zu is not valid\n",
Zhen Kong64a6d7282017-06-16 11:55:07 -07004530 app_name, strnlen(app_name, MAX_APP_NAME_SIZE));
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07004531 return -EINVAL;
4532 }
4533
4534 *handle = kzalloc(sizeof(struct qseecom_handle), GFP_KERNEL);
4535 if (!(*handle))
4536 return -ENOMEM;
4537
4538 data = kzalloc(sizeof(*data), GFP_KERNEL);
4539 if (!data) {
AnilKumar Chimatafe888722018-04-05 23:16:59 +05304540 ret = -ENOMEM;
4541 goto exit_handle_free;
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07004542 }
4543 data->abort = 0;
4544 data->type = QSEECOM_CLIENT_APP;
4545 data->released = false;
4546 data->client.sb_length = size;
4547 data->client.user_virt_sb_base = 0;
4548 data->client.ihandle = NULL;
4549
4550 init_waitqueue_head(&data->abort_wq);
4551
4552 data->client.ihandle = ion_alloc(qseecom.ion_clnt, size, 4096,
4553 ION_HEAP(ION_QSECOM_HEAP_ID), 0);
4554 if (IS_ERR_OR_NULL(data->client.ihandle)) {
4555 pr_err("Ion client could not retrieve the handle\n");
AnilKumar Chimatafe888722018-04-05 23:16:59 +05304556 ret = -ENOMEM;
4557 goto exit_data_free;
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07004558 }
4559 mutex_lock(&app_access_lock);
4560
Zhen Kong5d02be92018-05-29 16:17:29 -07004561recheck:
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07004562 app_ireq.qsee_cmd_id = QSEOS_APP_LOOKUP_COMMAND;
4563 strlcpy(app_ireq.app_name, app_name, MAX_APP_NAME_SIZE);
4564 ret = __qseecom_check_app_exists(app_ireq, &app_id);
4565 if (ret)
AnilKumar Chimatafe888722018-04-05 23:16:59 +05304566 goto exit_ion_free;
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07004567
4568 strlcpy(data->client.app_name, app_name, MAX_APP_NAME_SIZE);
4569 if (app_id) {
4570 pr_warn("App id %d for [%s] app exists\n", app_id,
4571 (char *)app_ireq.app_name);
4572 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
4573 list_for_each_entry(entry,
4574 &qseecom.registered_app_list_head, list){
4575 if (entry->app_id == app_id) {
4576 entry->ref_cnt++;
4577 found_app = true;
4578 break;
4579 }
4580 }
4581 spin_unlock_irqrestore(
4582 &qseecom.registered_app_list_lock, flags);
4583 if (!found_app)
4584 pr_warn("App_id %d [%s] was loaded but not registered\n",
4585 ret, (char *)app_ireq.app_name);
4586 } else {
4587 /* load the app and get the app_id */
4588 pr_debug("%s: Loading app for the first time'\n",
4589 qseecom.pdev->init_name);
4590 ret = __qseecom_load_fw(data, app_name, &app_id);
Zhen Kong5d02be92018-05-29 16:17:29 -07004591 if (ret == -EEXIST) {
4592 pr_err("recheck if TA %s is loaded\n", app_name);
4593 goto recheck;
4594 } else if (ret < 0)
AnilKumar Chimatafe888722018-04-05 23:16:59 +05304595 goto exit_ion_free;
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07004596 }
4597 data->client.app_id = app_id;
4598 if (!found_app) {
4599 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
4600 if (!entry) {
4601 pr_err("kmalloc for app entry failed\n");
AnilKumar Chimatafe888722018-04-05 23:16:59 +05304602 ret = -ENOMEM;
4603 goto exit_ion_free;
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07004604 }
4605 entry->app_id = app_id;
4606 entry->ref_cnt = 1;
4607 strlcpy(entry->app_name, app_name, MAX_APP_NAME_SIZE);
4608 if (__qseecom_get_fw_size(app_name, &fw_size, &app_arch)) {
4609 ret = -EIO;
AnilKumar Chimatafe888722018-04-05 23:16:59 +05304610 goto exit_entry_free;
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07004611 }
4612 entry->app_arch = app_arch;
4613 entry->app_blocked = false;
4614 entry->blocked_on_listener_id = 0;
Zhen Kongdea10592018-07-30 17:50:10 -07004615 entry->check_block = 0;
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07004616 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
4617 list_add_tail(&entry->list, &qseecom.registered_app_list_head);
4618 spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
4619 flags);
4620 }
4621
4622 /* Get the physical address of the ION BUF */
4623 ret = ion_phys(qseecom.ion_clnt, data->client.ihandle, &pa, &len);
4624 if (ret) {
4625 pr_err("Cannot get phys_addr for the Ion Client, ret = %d\n",
4626 ret);
AnilKumar Chimatafe888722018-04-05 23:16:59 +05304627 goto exit_entry_free;
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07004628 }
4629
4630 /* Populate the structure for sending scm call to load image */
4631 data->client.sb_virt = (char *) ion_map_kernel(qseecom.ion_clnt,
4632 data->client.ihandle);
4633 if (IS_ERR_OR_NULL(data->client.sb_virt)) {
4634 pr_err("ION memory mapping for client shared buf failed\n");
4635 ret = -ENOMEM;
AnilKumar Chimatafe888722018-04-05 23:16:59 +05304636 goto exit_entry_free;
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07004637 }
4638 data->client.user_virt_sb_base = (uintptr_t)data->client.sb_virt;
4639 data->client.sb_phys = (phys_addr_t)pa;
4640 (*handle)->dev = (void *)data;
4641 (*handle)->sbuf = (unsigned char *)data->client.sb_virt;
4642 (*handle)->sbuf_len = data->client.sb_length;
4643
4644 kclient_entry = kzalloc(sizeof(*kclient_entry), GFP_KERNEL);
4645 if (!kclient_entry) {
4646 ret = -ENOMEM;
AnilKumar Chimatafe888722018-04-05 23:16:59 +05304647 goto exit_ion_unmap_kernel;
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07004648 }
4649 kclient_entry->handle = *handle;
4650
4651 spin_lock_irqsave(&qseecom.registered_kclient_list_lock, flags);
4652 list_add_tail(&kclient_entry->list,
4653 &qseecom.registered_kclient_list_head);
4654 spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock, flags);
4655
4656 mutex_unlock(&app_access_lock);
4657 return 0;
4658
AnilKumar Chimatafe888722018-04-05 23:16:59 +05304659exit_ion_unmap_kernel:
4660 if (!IS_ERR_OR_NULL(data->client.ihandle))
4661 ion_unmap_kernel(qseecom.ion_clnt, data->client.ihandle);
4662exit_entry_free:
4663 kfree(entry);
4664exit_ion_free:
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07004665 mutex_unlock(&app_access_lock);
AnilKumar Chimatafe888722018-04-05 23:16:59 +05304666 if (!IS_ERR_OR_NULL(data->client.ihandle)) {
4667 ion_free(qseecom.ion_clnt, data->client.ihandle);
4668 data->client.ihandle = NULL;
4669 }
4670exit_data_free:
4671 kfree(data);
4672exit_handle_free:
4673 if (*handle) {
4674 kfree(*handle);
4675 *handle = NULL;
4676 }
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07004677 return ret;
4678}
4679EXPORT_SYMBOL(qseecom_start_app);
4680
4681int qseecom_shutdown_app(struct qseecom_handle **handle)
4682{
4683 int ret = -EINVAL;
4684 struct qseecom_dev_handle *data;
4685
4686 struct qseecom_registered_kclient_list *kclient = NULL;
4687 unsigned long flags = 0;
4688 bool found_handle = false;
4689
Zhen Kongbcdeda22018-11-16 13:50:51 -08004690 __qseecom_processing_pending_lsnr_unregister();
4691
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07004692 if (atomic_read(&qseecom.qseecom_state) != QSEECOM_STATE_READY) {
4693 pr_err("Not allowed to be called in %d state\n",
4694 atomic_read(&qseecom.qseecom_state));
4695 return -EPERM;
4696 }
4697
4698 if ((handle == NULL) || (*handle == NULL)) {
4699 pr_err("Handle is not initialized\n");
4700 return -EINVAL;
4701 }
4702 data = (struct qseecom_dev_handle *) ((*handle)->dev);
4703 mutex_lock(&app_access_lock);
4704
4705 spin_lock_irqsave(&qseecom.registered_kclient_list_lock, flags);
4706 list_for_each_entry(kclient, &qseecom.registered_kclient_list_head,
4707 list) {
4708 if (kclient->handle == (*handle)) {
4709 list_del(&kclient->list);
4710 found_handle = true;
4711 break;
4712 }
4713 }
4714 spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock, flags);
4715 if (!found_handle)
4716 pr_err("Unable to find the handle, exiting\n");
4717 else
4718 ret = qseecom_unload_app(data, false);
4719
4720 mutex_unlock(&app_access_lock);
4721 if (ret == 0) {
4722 kzfree(data);
4723 kzfree(*handle);
4724 kzfree(kclient);
4725 *handle = NULL;
4726 }
4727
4728 return ret;
4729}
4730EXPORT_SYMBOL(qseecom_shutdown_app);
4731
4732int qseecom_send_command(struct qseecom_handle *handle, void *send_buf,
4733 uint32_t sbuf_len, void *resp_buf, uint32_t rbuf_len)
4734{
4735 int ret = 0;
4736 struct qseecom_send_cmd_req req = {0, 0, 0, 0};
4737 struct qseecom_dev_handle *data;
4738 bool perf_enabled = false;
4739
Zhen Kongbcdeda22018-11-16 13:50:51 -08004740 __qseecom_processing_pending_lsnr_unregister();
4741
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07004742 if (atomic_read(&qseecom.qseecom_state) != QSEECOM_STATE_READY) {
4743 pr_err("Not allowed to be called in %d state\n",
4744 atomic_read(&qseecom.qseecom_state));
4745 return -EPERM;
4746 }
4747
4748 if (handle == NULL) {
4749 pr_err("Handle is not initialized\n");
4750 return -EINVAL;
4751 }
4752 data = handle->dev;
4753
4754 req.cmd_req_len = sbuf_len;
4755 req.resp_len = rbuf_len;
4756 req.cmd_req_buf = send_buf;
4757 req.resp_buf = resp_buf;
4758
4759 if (__validate_send_cmd_inputs(data, &req))
4760 return -EINVAL;
4761
4762 mutex_lock(&app_access_lock);
4763 if (qseecom.support_bus_scaling) {
4764 ret = qseecom_scale_bus_bandwidth_timer(INACTIVE);
4765 if (ret) {
4766 pr_err("Failed to set bw.\n");
4767 mutex_unlock(&app_access_lock);
4768 return ret;
4769 }
4770 }
4771 /*
4772 * On targets where crypto clock is handled by HLOS,
4773 * if clk_access_cnt is zero and perf_enabled is false,
4774 * then the crypto clock was not enabled before sending cmd
4775 * to tz, qseecom will enable the clock to avoid service failure.
4776 */
4777 if (!qseecom.no_clock_support &&
4778 !qseecom.qsee.clk_access_cnt && !data->perf_enabled) {
4779 pr_debug("ce clock is not enabled!\n");
4780 ret = qseecom_perf_enable(data);
4781 if (ret) {
4782 pr_err("Failed to vote for clock with err %d\n",
4783 ret);
4784 mutex_unlock(&app_access_lock);
4785 return -EINVAL;
4786 }
4787 perf_enabled = true;
4788 }
4789 if (!strcmp(data->client.app_name, "securemm"))
4790 data->use_legacy_cmd = true;
4791
4792 ret = __qseecom_send_cmd(data, &req);
4793 data->use_legacy_cmd = false;
4794 if (qseecom.support_bus_scaling)
4795 __qseecom_add_bw_scale_down_timer(
4796 QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
4797
4798 if (perf_enabled) {
4799 qsee_disable_clock_vote(data, CLK_DFAB);
4800 qsee_disable_clock_vote(data, CLK_SFPB);
4801 }
4802
4803 mutex_unlock(&app_access_lock);
4804
4805 if (ret)
4806 return ret;
4807
4808 pr_debug("sending cmd_req->rsp size: %u, ptr: 0x%pK\n",
4809 req.resp_len, req.resp_buf);
4810 return ret;
4811}
4812EXPORT_SYMBOL(qseecom_send_command);
4813
4814int qseecom_set_bandwidth(struct qseecom_handle *handle, bool high)
4815{
4816 int ret = 0;
4817
4818 if ((handle == NULL) || (handle->dev == NULL)) {
4819 pr_err("No valid kernel client\n");
4820 return -EINVAL;
4821 }
4822 if (high) {
4823 if (qseecom.support_bus_scaling) {
4824 mutex_lock(&qsee_bw_mutex);
4825 __qseecom_register_bus_bandwidth_needs(handle->dev,
4826 HIGH);
4827 mutex_unlock(&qsee_bw_mutex);
4828 } else {
4829 ret = qseecom_perf_enable(handle->dev);
4830 if (ret)
4831 pr_err("Failed to vote for clock with err %d\n",
4832 ret);
4833 }
4834 } else {
4835 if (!qseecom.support_bus_scaling) {
4836 qsee_disable_clock_vote(handle->dev, CLK_DFAB);
4837 qsee_disable_clock_vote(handle->dev, CLK_SFPB);
4838 } else {
4839 mutex_lock(&qsee_bw_mutex);
4840 qseecom_unregister_bus_bandwidth_needs(handle->dev);
4841 mutex_unlock(&qsee_bw_mutex);
4842 }
4843 }
4844 return ret;
4845}
4846EXPORT_SYMBOL(qseecom_set_bandwidth);
4847
4848int qseecom_process_listener_from_smcinvoke(struct scm_desc *desc)
4849{
4850 struct qseecom_registered_app_list dummy_app_entry = { {0} };
4851 struct qseecom_dev_handle dummy_private_data = {0};
4852 struct qseecom_command_scm_resp resp;
4853 int ret = 0;
4854
4855 if (!desc) {
4856 pr_err("desc is NULL\n");
4857 return -EINVAL;
4858 }
4859
4860 resp.result = desc->ret[0]; /*req_cmd*/
Zhen Kong2f60f492017-06-29 15:22:14 -07004861 resp.resp_type = desc->ret[1]; /*incomplete:unused;blocked:session_id*/
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07004862 resp.data = desc->ret[2]; /*listener_id*/
4863
Zhen Konge7f525f2017-12-01 18:26:25 -08004864 dummy_private_data.client.app_id = desc->ret[1];
4865 dummy_app_entry.app_id = desc->ret[1];
4866
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07004867 mutex_lock(&app_access_lock);
Zhen Kong7458c2e2017-10-19 12:32:07 -07004868 if (qseecom.qsee_reentrancy_support)
4869 ret = __qseecom_process_reentrancy(&resp, &dummy_app_entry,
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07004870 &dummy_private_data);
Zhen Kong7458c2e2017-10-19 12:32:07 -07004871 else
4872 ret = __qseecom_process_incomplete_cmd(&dummy_private_data,
4873 &resp);
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07004874 mutex_unlock(&app_access_lock);
4875 if (ret)
Zhen Kong2f60f492017-06-29 15:22:14 -07004876 pr_err("Failed on cmd %d for lsnr %d session %d, ret = %d\n",
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07004877 (int)desc->ret[0], (int)desc->ret[2],
4878 (int)desc->ret[1], ret);
4879 desc->ret[0] = resp.result;
4880 desc->ret[1] = resp.resp_type;
4881 desc->ret[2] = resp.data;
4882 return ret;
4883}
4884EXPORT_SYMBOL(qseecom_process_listener_from_smcinvoke);
4885
4886static int qseecom_send_resp(void)
4887{
4888 qseecom.send_resp_flag = 1;
4889 wake_up_interruptible(&qseecom.send_resp_wq);
4890 return 0;
4891}
4892
4893static int qseecom_reentrancy_send_resp(struct qseecom_dev_handle *data)
4894{
4895 struct qseecom_registered_listener_list *this_lstnr = NULL;
4896
4897 pr_debug("lstnr %d send resp, wakeup\n", data->listener.id);
4898 this_lstnr = __qseecom_find_svc(data->listener.id);
4899 if (this_lstnr == NULL)
4900 return -EINVAL;
4901 qseecom.send_resp_flag = 1;
4902 this_lstnr->send_resp_flag = 1;
4903 wake_up_interruptible(&qseecom.send_resp_wq);
4904 return 0;
4905}
4906
4907static int __validate_send_modfd_resp_inputs(struct qseecom_dev_handle *data,
4908 struct qseecom_send_modfd_listener_resp *resp,
4909 struct qseecom_registered_listener_list *this_lstnr)
4910{
4911 int i;
4912
4913 if (!data || !resp || !this_lstnr) {
4914 pr_err("listener handle or resp msg is null\n");
4915 return -EINVAL;
4916 }
4917
4918 if (resp->resp_buf_ptr == NULL) {
4919 pr_err("resp buffer is null\n");
4920 return -EINVAL;
4921 }
4922 /* validate resp buf length */
4923 if ((resp->resp_len == 0) ||
4924 (resp->resp_len > this_lstnr->sb_length)) {
4925 pr_err("resp buf length %d not valid\n", resp->resp_len);
4926 return -EINVAL;
4927 }
4928
4929 if ((uintptr_t)resp->resp_buf_ptr > (ULONG_MAX - resp->resp_len)) {
4930 pr_err("Integer overflow in resp_len & resp_buf\n");
4931 return -EINVAL;
4932 }
4933 if ((uintptr_t)this_lstnr->user_virt_sb_base >
4934 (ULONG_MAX - this_lstnr->sb_length)) {
4935 pr_err("Integer overflow in user_virt_sb_base & sb_length\n");
4936 return -EINVAL;
4937 }
4938 /* validate resp buf */
4939 if (((uintptr_t)resp->resp_buf_ptr <
4940 (uintptr_t)this_lstnr->user_virt_sb_base) ||
4941 ((uintptr_t)resp->resp_buf_ptr >=
4942 ((uintptr_t)this_lstnr->user_virt_sb_base +
4943 this_lstnr->sb_length)) ||
4944 (((uintptr_t)resp->resp_buf_ptr + resp->resp_len) >
4945 ((uintptr_t)this_lstnr->user_virt_sb_base +
4946 this_lstnr->sb_length))) {
4947 pr_err("resp buf is out of shared buffer region\n");
4948 return -EINVAL;
4949 }
4950
4951 /* validate offsets */
4952 for (i = 0; i < MAX_ION_FD; i++) {
4953 if (resp->ifd_data[i].cmd_buf_offset >= resp->resp_len) {
4954 pr_err("Invalid offset %d = 0x%x\n",
4955 i, resp->ifd_data[i].cmd_buf_offset);
4956 return -EINVAL;
4957 }
4958 }
4959
4960 return 0;
4961}
4962
4963static int __qseecom_send_modfd_resp(struct qseecom_dev_handle *data,
4964 void __user *argp, bool is_64bit_addr)
4965{
4966 struct qseecom_send_modfd_listener_resp resp;
4967 struct qseecom_registered_listener_list *this_lstnr = NULL;
4968
4969 if (copy_from_user(&resp, argp, sizeof(resp))) {
4970 pr_err("copy_from_user failed");
4971 return -EINVAL;
4972 }
4973
4974 this_lstnr = __qseecom_find_svc(data->listener.id);
4975 if (this_lstnr == NULL)
4976 return -EINVAL;
4977
4978 if (__validate_send_modfd_resp_inputs(data, &resp, this_lstnr))
4979 return -EINVAL;
4980
4981 resp.resp_buf_ptr = this_lstnr->sb_virt +
4982 (uintptr_t)(resp.resp_buf_ptr - this_lstnr->user_virt_sb_base);
4983
4984 if (!is_64bit_addr)
4985 __qseecom_update_cmd_buf(&resp, false, data);
4986 else
4987 __qseecom_update_cmd_buf_64(&resp, false, data);
4988 qseecom.send_resp_flag = 1;
4989 this_lstnr->send_resp_flag = 1;
4990 wake_up_interruptible(&qseecom.send_resp_wq);
4991 return 0;
4992}
4993
4994static int qseecom_send_modfd_resp(struct qseecom_dev_handle *data,
4995 void __user *argp)
4996{
4997 return __qseecom_send_modfd_resp(data, argp, false);
4998}
4999
5000static int qseecom_send_modfd_resp_64(struct qseecom_dev_handle *data,
5001 void __user *argp)
5002{
5003 return __qseecom_send_modfd_resp(data, argp, true);
5004}
5005
5006static int qseecom_get_qseos_version(struct qseecom_dev_handle *data,
5007 void __user *argp)
5008{
5009 struct qseecom_qseos_version_req req;
5010
5011 if (copy_from_user(&req, argp, sizeof(req))) {
5012 pr_err("copy_from_user failed");
5013 return -EINVAL;
5014 }
5015 req.qseos_version = qseecom.qseos_version;
5016 if (copy_to_user(argp, &req, sizeof(req))) {
5017 pr_err("copy_to_user failed");
5018 return -EINVAL;
5019 }
5020 return 0;
5021}
5022
5023static int __qseecom_enable_clk(enum qseecom_ce_hw_instance ce)
5024{
5025 int rc = 0;
5026 struct qseecom_clk *qclk = NULL;
5027
5028 if (qseecom.no_clock_support)
5029 return 0;
5030
5031 if (ce == CLK_QSEE)
5032 qclk = &qseecom.qsee;
5033 if (ce == CLK_CE_DRV)
5034 qclk = &qseecom.ce_drv;
5035
5036 if (qclk == NULL) {
5037 pr_err("CLK type not supported\n");
5038 return -EINVAL;
5039 }
5040 mutex_lock(&clk_access_lock);
5041
5042 if (qclk->clk_access_cnt == ULONG_MAX) {
5043 pr_err("clk_access_cnt beyond limitation\n");
5044 goto err;
5045 }
5046 if (qclk->clk_access_cnt > 0) {
5047 qclk->clk_access_cnt++;
5048 mutex_unlock(&clk_access_lock);
5049 return rc;
5050 }
5051
5052 /* Enable CE core clk */
5053 if (qclk->ce_core_clk != NULL) {
5054 rc = clk_prepare_enable(qclk->ce_core_clk);
5055 if (rc) {
5056 pr_err("Unable to enable/prepare CE core clk\n");
5057 goto err;
5058 }
5059 }
5060 /* Enable CE clk */
5061 if (qclk->ce_clk != NULL) {
5062 rc = clk_prepare_enable(qclk->ce_clk);
5063 if (rc) {
5064 pr_err("Unable to enable/prepare CE iface clk\n");
5065 goto ce_clk_err;
5066 }
5067 }
5068 /* Enable AXI clk */
5069 if (qclk->ce_bus_clk != NULL) {
5070 rc = clk_prepare_enable(qclk->ce_bus_clk);
5071 if (rc) {
5072 pr_err("Unable to enable/prepare CE bus clk\n");
5073 goto ce_bus_clk_err;
5074 }
5075 }
5076 qclk->clk_access_cnt++;
5077 mutex_unlock(&clk_access_lock);
5078 return 0;
5079
5080ce_bus_clk_err:
5081 if (qclk->ce_clk != NULL)
5082 clk_disable_unprepare(qclk->ce_clk);
5083ce_clk_err:
5084 if (qclk->ce_core_clk != NULL)
5085 clk_disable_unprepare(qclk->ce_core_clk);
5086err:
5087 mutex_unlock(&clk_access_lock);
5088 return -EIO;
5089}
5090
5091static void __qseecom_disable_clk(enum qseecom_ce_hw_instance ce)
5092{
5093 struct qseecom_clk *qclk;
5094
5095 if (qseecom.no_clock_support)
5096 return;
5097
5098 if (ce == CLK_QSEE)
5099 qclk = &qseecom.qsee;
5100 else
5101 qclk = &qseecom.ce_drv;
5102
5103 mutex_lock(&clk_access_lock);
5104
5105 if (qclk->clk_access_cnt == 0) {
5106 mutex_unlock(&clk_access_lock);
5107 return;
5108 }
5109
5110 if (qclk->clk_access_cnt == 1) {
5111 if (qclk->ce_clk != NULL)
5112 clk_disable_unprepare(qclk->ce_clk);
5113 if (qclk->ce_core_clk != NULL)
5114 clk_disable_unprepare(qclk->ce_core_clk);
5115 if (qclk->ce_bus_clk != NULL)
5116 clk_disable_unprepare(qclk->ce_bus_clk);
5117 }
5118 qclk->clk_access_cnt--;
5119 mutex_unlock(&clk_access_lock);
5120}
5121
5122static int qsee_vote_for_clock(struct qseecom_dev_handle *data,
5123 int32_t clk_type)
5124{
5125 int ret = 0;
5126 struct qseecom_clk *qclk;
5127
5128 if (qseecom.no_clock_support)
5129 return 0;
5130
5131 qclk = &qseecom.qsee;
5132 if (!qseecom.qsee_perf_client)
5133 return ret;
5134
5135 switch (clk_type) {
5136 case CLK_DFAB:
5137 mutex_lock(&qsee_bw_mutex);
5138 if (!qseecom.qsee_bw_count) {
5139 if (qseecom.qsee_sfpb_bw_count > 0)
5140 ret = msm_bus_scale_client_update_request(
5141 qseecom.qsee_perf_client, 3);
5142 else {
5143 if (qclk->ce_core_src_clk != NULL)
5144 ret = __qseecom_enable_clk(CLK_QSEE);
5145 if (!ret) {
5146 ret =
5147 msm_bus_scale_client_update_request(
5148 qseecom.qsee_perf_client, 1);
5149 if ((ret) &&
5150 (qclk->ce_core_src_clk != NULL))
5151 __qseecom_disable_clk(CLK_QSEE);
5152 }
5153 }
5154 if (ret)
5155 pr_err("DFAB Bandwidth req failed (%d)\n",
5156 ret);
5157 else {
5158 qseecom.qsee_bw_count++;
5159 data->perf_enabled = true;
5160 }
5161 } else {
5162 qseecom.qsee_bw_count++;
5163 data->perf_enabled = true;
5164 }
5165 mutex_unlock(&qsee_bw_mutex);
5166 break;
5167 case CLK_SFPB:
5168 mutex_lock(&qsee_bw_mutex);
5169 if (!qseecom.qsee_sfpb_bw_count) {
5170 if (qseecom.qsee_bw_count > 0)
5171 ret = msm_bus_scale_client_update_request(
5172 qseecom.qsee_perf_client, 3);
5173 else {
5174 if (qclk->ce_core_src_clk != NULL)
5175 ret = __qseecom_enable_clk(CLK_QSEE);
5176 if (!ret) {
5177 ret =
5178 msm_bus_scale_client_update_request(
5179 qseecom.qsee_perf_client, 2);
5180 if ((ret) &&
5181 (qclk->ce_core_src_clk != NULL))
5182 __qseecom_disable_clk(CLK_QSEE);
5183 }
5184 }
5185
5186 if (ret)
5187 pr_err("SFPB Bandwidth req failed (%d)\n",
5188 ret);
5189 else {
5190 qseecom.qsee_sfpb_bw_count++;
5191 data->fast_load_enabled = true;
5192 }
5193 } else {
5194 qseecom.qsee_sfpb_bw_count++;
5195 data->fast_load_enabled = true;
5196 }
5197 mutex_unlock(&qsee_bw_mutex);
5198 break;
5199 default:
5200 pr_err("Clock type not defined\n");
5201 break;
5202 }
5203 return ret;
5204}
5205
5206static void qsee_disable_clock_vote(struct qseecom_dev_handle *data,
5207 int32_t clk_type)
5208{
5209 int32_t ret = 0;
5210 struct qseecom_clk *qclk;
5211
5212 qclk = &qseecom.qsee;
5213
5214 if (qseecom.no_clock_support)
5215 return;
5216 if (!qseecom.qsee_perf_client)
5217 return;
5218
5219 switch (clk_type) {
5220 case CLK_DFAB:
5221 mutex_lock(&qsee_bw_mutex);
5222 if (qseecom.qsee_bw_count == 0) {
5223 pr_err("Client error.Extra call to disable DFAB clk\n");
5224 mutex_unlock(&qsee_bw_mutex);
5225 return;
5226 }
5227
5228 if (qseecom.qsee_bw_count == 1) {
5229 if (qseecom.qsee_sfpb_bw_count > 0)
5230 ret = msm_bus_scale_client_update_request(
5231 qseecom.qsee_perf_client, 2);
5232 else {
5233 ret = msm_bus_scale_client_update_request(
5234 qseecom.qsee_perf_client, 0);
5235 if ((!ret) && (qclk->ce_core_src_clk != NULL))
5236 __qseecom_disable_clk(CLK_QSEE);
5237 }
5238 if (ret)
5239 pr_err("SFPB Bandwidth req fail (%d)\n",
5240 ret);
5241 else {
5242 qseecom.qsee_bw_count--;
5243 data->perf_enabled = false;
5244 }
5245 } else {
5246 qseecom.qsee_bw_count--;
5247 data->perf_enabled = false;
5248 }
5249 mutex_unlock(&qsee_bw_mutex);
5250 break;
5251 case CLK_SFPB:
5252 mutex_lock(&qsee_bw_mutex);
5253 if (qseecom.qsee_sfpb_bw_count == 0) {
5254 pr_err("Client error.Extra call to disable SFPB clk\n");
5255 mutex_unlock(&qsee_bw_mutex);
5256 return;
5257 }
5258 if (qseecom.qsee_sfpb_bw_count == 1) {
5259 if (qseecom.qsee_bw_count > 0)
5260 ret = msm_bus_scale_client_update_request(
5261 qseecom.qsee_perf_client, 1);
5262 else {
5263 ret = msm_bus_scale_client_update_request(
5264 qseecom.qsee_perf_client, 0);
5265 if ((!ret) && (qclk->ce_core_src_clk != NULL))
5266 __qseecom_disable_clk(CLK_QSEE);
5267 }
5268 if (ret)
5269 pr_err("SFPB Bandwidth req fail (%d)\n",
5270 ret);
5271 else {
5272 qseecom.qsee_sfpb_bw_count--;
5273 data->fast_load_enabled = false;
5274 }
5275 } else {
5276 qseecom.qsee_sfpb_bw_count--;
5277 data->fast_load_enabled = false;
5278 }
5279 mutex_unlock(&qsee_bw_mutex);
5280 break;
5281 default:
5282 pr_err("Clock type not defined\n");
5283 break;
5284 }
5285
5286}
5287
5288static int qseecom_load_external_elf(struct qseecom_dev_handle *data,
5289 void __user *argp)
5290{
5291 struct ion_handle *ihandle; /* Ion handle */
5292 struct qseecom_load_img_req load_img_req;
5293 int uret = 0;
5294 int ret;
5295 ion_phys_addr_t pa = 0;
5296 size_t len;
5297 struct qseecom_load_app_ireq load_req;
5298 struct qseecom_load_app_64bit_ireq load_req_64bit;
5299 struct qseecom_command_scm_resp resp;
5300 void *cmd_buf = NULL;
5301 size_t cmd_len;
5302 /* Copy the relevant information needed for loading the image */
5303 if (copy_from_user(&load_img_req,
5304 (void __user *)argp,
5305 sizeof(struct qseecom_load_img_req))) {
5306 pr_err("copy_from_user failed\n");
5307 return -EFAULT;
5308 }
5309
5310 /* Get the handle of the shared fd */
AnilKumar Chimata04d60cf2017-04-09 11:43:10 -07005311 ihandle = ion_import_dma_buf_fd(qseecom.ion_clnt,
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07005312 load_img_req.ifd_data_fd);
5313 if (IS_ERR_OR_NULL(ihandle)) {
5314 pr_err("Ion client could not retrieve the handle\n");
5315 return -ENOMEM;
5316 }
5317
5318 /* Get the physical address of the ION BUF */
5319 ret = ion_phys(qseecom.ion_clnt, ihandle, &pa, &len);
5320 if (ret) {
5321 pr_err("Cannot get phys_addr for the Ion Client, ret = %d\n",
5322 ret);
5323 return ret;
5324 }
5325 if (load_img_req.mdt_len > len || load_img_req.img_len > len) {
5326 pr_err("ion len %zu is smaller than mdt_len %u or img_len %u\n",
5327 len, load_img_req.mdt_len,
5328 load_img_req.img_len);
5329 return ret;
5330 }
5331 /* Populate the structure for sending scm call to load image */
5332 if (qseecom.qsee_version < QSEE_VERSION_40) {
5333 load_req.qsee_cmd_id = QSEOS_LOAD_EXTERNAL_ELF_COMMAND;
5334 load_req.mdt_len = load_img_req.mdt_len;
5335 load_req.img_len = load_img_req.img_len;
5336 load_req.phy_addr = (uint32_t)pa;
5337 cmd_buf = (void *)&load_req;
5338 cmd_len = sizeof(struct qseecom_load_app_ireq);
5339 } else {
5340 load_req_64bit.qsee_cmd_id = QSEOS_LOAD_EXTERNAL_ELF_COMMAND;
5341 load_req_64bit.mdt_len = load_img_req.mdt_len;
5342 load_req_64bit.img_len = load_img_req.img_len;
5343 load_req_64bit.phy_addr = (uint64_t)pa;
5344 cmd_buf = (void *)&load_req_64bit;
5345 cmd_len = sizeof(struct qseecom_load_app_64bit_ireq);
5346 }
5347
5348 if (qseecom.support_bus_scaling) {
5349 mutex_lock(&qsee_bw_mutex);
5350 ret = __qseecom_register_bus_bandwidth_needs(data, MEDIUM);
5351 mutex_unlock(&qsee_bw_mutex);
5352 if (ret) {
5353 ret = -EIO;
5354 goto exit_cpu_restore;
5355 }
5356 }
5357
5358 /* Vote for the SFPB clock */
5359 ret = __qseecom_enable_clk_scale_up(data);
5360 if (ret) {
5361 ret = -EIO;
5362 goto exit_register_bus_bandwidth_needs;
5363 }
5364 ret = msm_ion_do_cache_op(qseecom.ion_clnt, ihandle, NULL, len,
5365 ION_IOC_CLEAN_INV_CACHES);
5366 if (ret) {
5367 pr_err("cache operation failed %d\n", ret);
5368 goto exit_disable_clock;
5369 }
5370 /* SCM_CALL to load the external elf */
5371 ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, cmd_buf, cmd_len,
5372 &resp, sizeof(resp));
5373 if (ret) {
5374 pr_err("scm_call to load failed : ret %d\n",
5375 ret);
5376 ret = -EFAULT;
5377 goto exit_disable_clock;
5378 }
5379
5380 switch (resp.result) {
5381 case QSEOS_RESULT_SUCCESS:
5382 break;
5383 case QSEOS_RESULT_INCOMPLETE:
5384 pr_err("%s: qseos result incomplete\n", __func__);
5385 ret = __qseecom_process_incomplete_cmd(data, &resp);
5386 if (ret)
5387 pr_err("process_incomplete_cmd failed: err: %d\n", ret);
5388 break;
5389 case QSEOS_RESULT_FAILURE:
5390 pr_err("scm_call rsp.result is QSEOS_RESULT_FAILURE\n");
5391 ret = -EFAULT;
5392 break;
5393 default:
5394 pr_err("scm_call response result %d not supported\n",
5395 resp.result);
5396 ret = -EFAULT;
5397 break;
5398 }
5399
5400exit_disable_clock:
5401 __qseecom_disable_clk_scale_down(data);
5402
5403exit_register_bus_bandwidth_needs:
5404 if (qseecom.support_bus_scaling) {
5405 mutex_lock(&qsee_bw_mutex);
5406 uret = qseecom_unregister_bus_bandwidth_needs(data);
5407 mutex_unlock(&qsee_bw_mutex);
5408 if (uret)
5409 pr_err("Failed to unregister bus bw needs %d, scm_call ret %d\n",
5410 uret, ret);
5411 }
5412
5413exit_cpu_restore:
5414 /* Deallocate the handle */
5415 if (!IS_ERR_OR_NULL(ihandle))
5416 ion_free(qseecom.ion_clnt, ihandle);
5417 return ret;
5418}
5419
5420static int qseecom_unload_external_elf(struct qseecom_dev_handle *data)
5421{
5422 int ret = 0;
5423 struct qseecom_command_scm_resp resp;
5424 struct qseecom_unload_app_ireq req;
5425
5426 /* unavailable client app */
5427 data->type = QSEECOM_UNAVAILABLE_CLIENT_APP;
5428
5429 /* Populate the structure for sending scm call to unload image */
5430 req.qsee_cmd_id = QSEOS_UNLOAD_EXTERNAL_ELF_COMMAND;
5431
5432 /* SCM_CALL to unload the external elf */
5433 ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
5434 sizeof(struct qseecom_unload_app_ireq),
5435 &resp, sizeof(resp));
5436 if (ret) {
5437 pr_err("scm_call to unload failed : ret %d\n",
5438 ret);
5439 ret = -EFAULT;
5440 goto qseecom_unload_external_elf_scm_err;
5441 }
5442 if (resp.result == QSEOS_RESULT_INCOMPLETE) {
5443 ret = __qseecom_process_incomplete_cmd(data, &resp);
5444 if (ret)
5445 pr_err("process_incomplete_cmd fail err: %d\n",
5446 ret);
5447 } else {
5448 if (resp.result != QSEOS_RESULT_SUCCESS) {
5449 pr_err("scm_call to unload image failed resp.result =%d\n",
5450 resp.result);
5451 ret = -EFAULT;
5452 }
5453 }
5454
5455qseecom_unload_external_elf_scm_err:
5456
5457 return ret;
5458}
5459
5460static int qseecom_query_app_loaded(struct qseecom_dev_handle *data,
5461 void __user *argp)
5462{
5463
5464 int32_t ret;
5465 struct qseecom_qseos_app_load_query query_req;
5466 struct qseecom_check_app_ireq req;
5467 struct qseecom_registered_app_list *entry = NULL;
5468 unsigned long flags = 0;
5469 uint32_t app_arch = 0, app_id = 0;
5470 bool found_app = false;
5471
5472 /* Copy the relevant information needed for loading the image */
5473 if (copy_from_user(&query_req,
5474 (void __user *)argp,
5475 sizeof(struct qseecom_qseos_app_load_query))) {
5476 pr_err("copy_from_user failed\n");
5477 return -EFAULT;
5478 }
5479
5480 req.qsee_cmd_id = QSEOS_APP_LOOKUP_COMMAND;
5481 query_req.app_name[MAX_APP_NAME_SIZE-1] = '\0';
5482 strlcpy(req.app_name, query_req.app_name, MAX_APP_NAME_SIZE);
5483
5484 ret = __qseecom_check_app_exists(req, &app_id);
5485 if (ret) {
5486 pr_err(" scm call to check if app is loaded failed");
5487 return ret; /* scm call failed */
5488 }
5489 if (app_id) {
5490 pr_debug("App id %d (%s) already exists\n", app_id,
5491 (char *)(req.app_name));
5492 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
5493 list_for_each_entry(entry,
5494 &qseecom.registered_app_list_head, list){
5495 if (entry->app_id == app_id) {
5496 app_arch = entry->app_arch;
5497 entry->ref_cnt++;
5498 found_app = true;
5499 break;
5500 }
5501 }
5502 spin_unlock_irqrestore(
5503 &qseecom.registered_app_list_lock, flags);
5504 data->client.app_id = app_id;
5505 query_req.app_id = app_id;
5506 if (app_arch) {
5507 data->client.app_arch = app_arch;
5508 query_req.app_arch = app_arch;
5509 } else {
5510 data->client.app_arch = 0;
5511 query_req.app_arch = 0;
5512 }
5513 strlcpy(data->client.app_name, query_req.app_name,
5514 MAX_APP_NAME_SIZE);
5515 /*
5516 * If app was loaded by appsbl before and was not registered,
5517 * regiser this app now.
5518 */
5519 if (!found_app) {
5520 pr_debug("Register app %d [%s] which was loaded before\n",
5521 ret, (char *)query_req.app_name);
5522 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
5523 if (!entry) {
5524 pr_err("kmalloc for app entry failed\n");
5525 return -ENOMEM;
5526 }
5527 entry->app_id = app_id;
5528 entry->ref_cnt = 1;
5529 entry->app_arch = data->client.app_arch;
5530 strlcpy(entry->app_name, data->client.app_name,
5531 MAX_APP_NAME_SIZE);
5532 entry->app_blocked = false;
5533 entry->blocked_on_listener_id = 0;
Zhen Kongdea10592018-07-30 17:50:10 -07005534 entry->check_block = 0;
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07005535 spin_lock_irqsave(&qseecom.registered_app_list_lock,
5536 flags);
5537 list_add_tail(&entry->list,
5538 &qseecom.registered_app_list_head);
5539 spin_unlock_irqrestore(
5540 &qseecom.registered_app_list_lock, flags);
5541 }
5542 if (copy_to_user(argp, &query_req, sizeof(query_req))) {
5543 pr_err("copy_to_user failed\n");
5544 return -EFAULT;
5545 }
5546 return -EEXIST; /* app already loaded */
5547 } else {
5548 return 0; /* app not loaded */
5549 }
5550}
5551
5552static int __qseecom_get_ce_pipe_info(
5553 enum qseecom_key_management_usage_type usage,
5554 uint32_t *pipe, uint32_t **ce_hw, uint32_t unit)
5555{
5556 int ret = -EINVAL;
5557 int i, j;
5558 struct qseecom_ce_info_use *p = NULL;
5559 int total = 0;
5560 struct qseecom_ce_pipe_entry *pcepipe;
5561
5562 switch (usage) {
5563 case QSEOS_KM_USAGE_DISK_ENCRYPTION:
5564 case QSEOS_KM_USAGE_UFS_ICE_DISK_ENCRYPTION:
5565 case QSEOS_KM_USAGE_SDCC_ICE_DISK_ENCRYPTION:
5566 if (qseecom.support_fde) {
5567 p = qseecom.ce_info.fde;
5568 total = qseecom.ce_info.num_fde;
5569 } else {
5570 pr_err("system does not support fde\n");
5571 return -EINVAL;
5572 }
5573 break;
5574 case QSEOS_KM_USAGE_FILE_ENCRYPTION:
5575 if (qseecom.support_pfe) {
5576 p = qseecom.ce_info.pfe;
5577 total = qseecom.ce_info.num_pfe;
5578 } else {
5579 pr_err("system does not support pfe\n");
5580 return -EINVAL;
5581 }
5582 break;
5583 default:
5584 pr_err("unsupported usage %d\n", usage);
5585 return -EINVAL;
5586 }
5587
5588 for (j = 0; j < total; j++) {
5589 if (p->unit_num == unit) {
5590 pcepipe = p->ce_pipe_entry;
5591 for (i = 0; i < p->num_ce_pipe_entries; i++) {
5592 (*ce_hw)[i] = pcepipe->ce_num;
5593 *pipe = pcepipe->ce_pipe_pair;
5594 pcepipe++;
5595 }
5596 ret = 0;
5597 break;
5598 }
5599 p++;
5600 }
5601 return ret;
5602}
5603
5604static int __qseecom_generate_and_save_key(struct qseecom_dev_handle *data,
5605 enum qseecom_key_management_usage_type usage,
5606 struct qseecom_key_generate_ireq *ireq)
5607{
5608 struct qseecom_command_scm_resp resp;
5609 int ret;
5610
5611 if (usage < QSEOS_KM_USAGE_DISK_ENCRYPTION ||
5612 usage >= QSEOS_KM_USAGE_MAX) {
5613 pr_err("Error:: unsupported usage %d\n", usage);
5614 return -EFAULT;
5615 }
5616 ret = __qseecom_enable_clk(CLK_QSEE);
5617 if (ret)
5618 return ret;
5619
5620 ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1,
5621 ireq, sizeof(struct qseecom_key_generate_ireq),
5622 &resp, sizeof(resp));
5623 if (ret) {
5624 if (ret == -EINVAL &&
5625 resp.result == QSEOS_RESULT_FAIL_KEY_ID_EXISTS) {
5626 pr_debug("Key ID exists.\n");
5627 ret = 0;
5628 } else {
5629 pr_err("scm call to generate key failed : %d\n", ret);
5630 ret = -EFAULT;
5631 }
5632 goto generate_key_exit;
5633 }
5634
5635 switch (resp.result) {
5636 case QSEOS_RESULT_SUCCESS:
5637 break;
5638 case QSEOS_RESULT_FAIL_KEY_ID_EXISTS:
5639 pr_debug("Key ID exists.\n");
5640 break;
5641 case QSEOS_RESULT_INCOMPLETE:
5642 ret = __qseecom_process_incomplete_cmd(data, &resp);
5643 if (ret) {
5644 if (resp.result == QSEOS_RESULT_FAIL_KEY_ID_EXISTS) {
5645 pr_debug("Key ID exists.\n");
5646 ret = 0;
5647 } else {
5648 pr_err("process_incomplete_cmd FAILED, resp.result %d\n",
5649 resp.result);
5650 }
5651 }
5652 break;
5653 case QSEOS_RESULT_FAILURE:
5654 default:
5655 pr_err("gen key scm call failed resp.result %d\n", resp.result);
5656 ret = -EINVAL;
5657 break;
5658 }
5659generate_key_exit:
5660 __qseecom_disable_clk(CLK_QSEE);
5661 return ret;
5662}
5663
5664static int __qseecom_delete_saved_key(struct qseecom_dev_handle *data,
5665 enum qseecom_key_management_usage_type usage,
5666 struct qseecom_key_delete_ireq *ireq)
5667{
5668 struct qseecom_command_scm_resp resp;
5669 int ret;
5670
5671 if (usage < QSEOS_KM_USAGE_DISK_ENCRYPTION ||
5672 usage >= QSEOS_KM_USAGE_MAX) {
5673 pr_err("Error:: unsupported usage %d\n", usage);
5674 return -EFAULT;
5675 }
5676 ret = __qseecom_enable_clk(CLK_QSEE);
5677 if (ret)
5678 return ret;
5679
5680 ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1,
5681 ireq, sizeof(struct qseecom_key_delete_ireq),
5682 &resp, sizeof(struct qseecom_command_scm_resp));
5683 if (ret) {
5684 if (ret == -EINVAL &&
5685 resp.result == QSEOS_RESULT_FAIL_MAX_ATTEMPT) {
5686 pr_debug("Max attempts to input password reached.\n");
5687 ret = -ERANGE;
5688 } else {
5689 pr_err("scm call to delete key failed : %d\n", ret);
5690 ret = -EFAULT;
5691 }
5692 goto del_key_exit;
5693 }
5694
5695 switch (resp.result) {
5696 case QSEOS_RESULT_SUCCESS:
5697 break;
5698 case QSEOS_RESULT_INCOMPLETE:
5699 ret = __qseecom_process_incomplete_cmd(data, &resp);
5700 if (ret) {
5701 pr_err("process_incomplete_cmd FAILED, resp.result %d\n",
5702 resp.result);
5703 if (resp.result == QSEOS_RESULT_FAIL_MAX_ATTEMPT) {
5704 pr_debug("Max attempts to input password reached.\n");
5705 ret = -ERANGE;
5706 }
5707 }
5708 break;
5709 case QSEOS_RESULT_FAIL_MAX_ATTEMPT:
5710 pr_debug("Max attempts to input password reached.\n");
5711 ret = -ERANGE;
5712 break;
5713 case QSEOS_RESULT_FAILURE:
5714 default:
5715 pr_err("Delete key scm call failed resp.result %d\n",
5716 resp.result);
5717 ret = -EINVAL;
5718 break;
5719 }
5720del_key_exit:
5721 __qseecom_disable_clk(CLK_QSEE);
5722 return ret;
5723}
5724
5725static int __qseecom_set_clear_ce_key(struct qseecom_dev_handle *data,
5726 enum qseecom_key_management_usage_type usage,
5727 struct qseecom_key_select_ireq *ireq)
5728{
5729 struct qseecom_command_scm_resp resp;
5730 int ret;
5731
5732 if (usage < QSEOS_KM_USAGE_DISK_ENCRYPTION ||
5733 usage >= QSEOS_KM_USAGE_MAX) {
5734 pr_err("Error:: unsupported usage %d\n", usage);
5735 return -EFAULT;
5736 }
5737 ret = __qseecom_enable_clk(CLK_QSEE);
5738 if (ret)
5739 return ret;
5740
5741 if (qseecom.qsee.instance != qseecom.ce_drv.instance) {
5742 ret = __qseecom_enable_clk(CLK_CE_DRV);
5743 if (ret)
5744 return ret;
5745 }
5746
5747 ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1,
5748 ireq, sizeof(struct qseecom_key_select_ireq),
5749 &resp, sizeof(struct qseecom_command_scm_resp));
5750 if (ret) {
5751 if (ret == -EINVAL &&
5752 resp.result == QSEOS_RESULT_FAIL_MAX_ATTEMPT) {
5753 pr_debug("Max attempts to input password reached.\n");
5754 ret = -ERANGE;
5755 } else if (ret == -EINVAL &&
5756 resp.result == QSEOS_RESULT_FAIL_PENDING_OPERATION) {
5757 pr_debug("Set Key operation under processing...\n");
5758 ret = QSEOS_RESULT_FAIL_PENDING_OPERATION;
5759 } else {
5760 pr_err("scm call to set QSEOS_PIPE_ENC key failed : %d\n",
5761 ret);
5762 ret = -EFAULT;
5763 }
5764 goto set_key_exit;
5765 }
5766
5767 switch (resp.result) {
5768 case QSEOS_RESULT_SUCCESS:
5769 break;
5770 case QSEOS_RESULT_INCOMPLETE:
5771 ret = __qseecom_process_incomplete_cmd(data, &resp);
5772 if (ret) {
5773 pr_err("process_incomplete_cmd FAILED, resp.result %d\n",
5774 resp.result);
5775 if (resp.result ==
5776 QSEOS_RESULT_FAIL_PENDING_OPERATION) {
5777 pr_debug("Set Key operation under processing...\n");
5778 ret = QSEOS_RESULT_FAIL_PENDING_OPERATION;
5779 }
5780 if (resp.result == QSEOS_RESULT_FAIL_MAX_ATTEMPT) {
5781 pr_debug("Max attempts to input password reached.\n");
5782 ret = -ERANGE;
5783 }
5784 }
5785 break;
5786 case QSEOS_RESULT_FAIL_MAX_ATTEMPT:
5787 pr_debug("Max attempts to input password reached.\n");
5788 ret = -ERANGE;
5789 break;
5790 case QSEOS_RESULT_FAIL_PENDING_OPERATION:
5791 pr_debug("Set Key operation under processing...\n");
5792 ret = QSEOS_RESULT_FAIL_PENDING_OPERATION;
5793 break;
5794 case QSEOS_RESULT_FAILURE:
5795 default:
5796 pr_err("Set key scm call failed resp.result %d\n", resp.result);
5797 ret = -EINVAL;
5798 break;
5799 }
5800set_key_exit:
5801 __qseecom_disable_clk(CLK_QSEE);
5802 if (qseecom.qsee.instance != qseecom.ce_drv.instance)
5803 __qseecom_disable_clk(CLK_CE_DRV);
5804 return ret;
5805}
5806
5807static int __qseecom_update_current_key_user_info(
5808 struct qseecom_dev_handle *data,
5809 enum qseecom_key_management_usage_type usage,
5810 struct qseecom_key_userinfo_update_ireq *ireq)
5811{
5812 struct qseecom_command_scm_resp resp;
5813 int ret;
5814
5815 if (usage < QSEOS_KM_USAGE_DISK_ENCRYPTION ||
5816 usage >= QSEOS_KM_USAGE_MAX) {
5817 pr_err("Error:: unsupported usage %d\n", usage);
5818 return -EFAULT;
5819 }
5820 ret = __qseecom_enable_clk(CLK_QSEE);
5821 if (ret)
5822 return ret;
5823
5824 ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1,
5825 ireq, sizeof(struct qseecom_key_userinfo_update_ireq),
5826 &resp, sizeof(struct qseecom_command_scm_resp));
5827 if (ret) {
5828 if (ret == -EINVAL &&
5829 resp.result == QSEOS_RESULT_FAIL_PENDING_OPERATION) {
5830 pr_debug("Set Key operation under processing...\n");
5831 ret = QSEOS_RESULT_FAIL_PENDING_OPERATION;
5832 } else {
5833 pr_err("scm call to update key userinfo failed: %d\n",
5834 ret);
5835 __qseecom_disable_clk(CLK_QSEE);
5836 return -EFAULT;
5837 }
5838 }
5839
5840 switch (resp.result) {
5841 case QSEOS_RESULT_SUCCESS:
5842 break;
5843 case QSEOS_RESULT_INCOMPLETE:
5844 ret = __qseecom_process_incomplete_cmd(data, &resp);
5845 if (resp.result ==
5846 QSEOS_RESULT_FAIL_PENDING_OPERATION) {
5847 pr_debug("Set Key operation under processing...\n");
5848 ret = QSEOS_RESULT_FAIL_PENDING_OPERATION;
5849 }
5850 if (ret)
5851 pr_err("process_incomplete_cmd FAILED, resp.result %d\n",
5852 resp.result);
5853 break;
5854 case QSEOS_RESULT_FAIL_PENDING_OPERATION:
5855 pr_debug("Update Key operation under processing...\n");
5856 ret = QSEOS_RESULT_FAIL_PENDING_OPERATION;
5857 break;
5858 case QSEOS_RESULT_FAILURE:
5859 default:
5860 pr_err("Set key scm call failed resp.result %d\n", resp.result);
5861 ret = -EINVAL;
5862 break;
5863 }
5864
5865 __qseecom_disable_clk(CLK_QSEE);
5866 return ret;
5867}
5868
5869
5870static int qseecom_enable_ice_setup(int usage)
5871{
5872 int ret = 0;
5873
5874 if (usage == QSEOS_KM_USAGE_UFS_ICE_DISK_ENCRYPTION)
5875 ret = qcom_ice_setup_ice_hw("ufs", true);
5876 else if (usage == QSEOS_KM_USAGE_SDCC_ICE_DISK_ENCRYPTION)
5877 ret = qcom_ice_setup_ice_hw("sdcc", true);
5878
5879 return ret;
5880}
5881
5882static int qseecom_disable_ice_setup(int usage)
5883{
5884 int ret = 0;
5885
5886 if (usage == QSEOS_KM_USAGE_UFS_ICE_DISK_ENCRYPTION)
5887 ret = qcom_ice_setup_ice_hw("ufs", false);
5888 else if (usage == QSEOS_KM_USAGE_SDCC_ICE_DISK_ENCRYPTION)
5889 ret = qcom_ice_setup_ice_hw("sdcc", false);
5890
5891 return ret;
5892}
5893
5894static int qseecom_get_ce_hw_instance(uint32_t unit, uint32_t usage)
5895{
5896 struct qseecom_ce_info_use *pce_info_use, *p;
5897 int total = 0;
5898 int i;
5899
5900 switch (usage) {
5901 case QSEOS_KM_USAGE_DISK_ENCRYPTION:
5902 case QSEOS_KM_USAGE_UFS_ICE_DISK_ENCRYPTION:
5903 case QSEOS_KM_USAGE_SDCC_ICE_DISK_ENCRYPTION:
5904 p = qseecom.ce_info.fde;
5905 total = qseecom.ce_info.num_fde;
5906 break;
5907 case QSEOS_KM_USAGE_FILE_ENCRYPTION:
5908 p = qseecom.ce_info.pfe;
5909 total = qseecom.ce_info.num_pfe;
5910 break;
5911 default:
5912 pr_err("unsupported usage %d\n", usage);
5913 return -EINVAL;
5914 }
5915
5916 pce_info_use = NULL;
5917
5918 for (i = 0; i < total; i++) {
5919 if (p->unit_num == unit) {
5920 pce_info_use = p;
5921 break;
5922 }
5923 p++;
5924 }
5925 if (!pce_info_use) {
5926 pr_err("can not find %d\n", unit);
5927 return -EINVAL;
5928 }
5929 return pce_info_use->num_ce_pipe_entries;
5930}
5931
5932static int qseecom_create_key(struct qseecom_dev_handle *data,
5933 void __user *argp)
5934{
5935 int i;
5936 uint32_t *ce_hw = NULL;
5937 uint32_t pipe = 0;
5938 int ret = 0;
5939 uint32_t flags = 0;
5940 struct qseecom_create_key_req create_key_req;
5941 struct qseecom_key_generate_ireq generate_key_ireq;
5942 struct qseecom_key_select_ireq set_key_ireq;
5943 uint32_t entries = 0;
5944
5945 ret = copy_from_user(&create_key_req, argp, sizeof(create_key_req));
5946 if (ret) {
5947 pr_err("copy_from_user failed\n");
5948 return ret;
5949 }
5950
5951 if (create_key_req.usage < QSEOS_KM_USAGE_DISK_ENCRYPTION ||
5952 create_key_req.usage >= QSEOS_KM_USAGE_MAX) {
5953 pr_err("unsupported usage %d\n", create_key_req.usage);
5954 ret = -EFAULT;
5955 return ret;
5956 }
5957 entries = qseecom_get_ce_hw_instance(DEFAULT_CE_INFO_UNIT,
5958 create_key_req.usage);
5959 if (entries <= 0) {
5960 pr_err("no ce instance for usage %d instance %d\n",
5961 DEFAULT_CE_INFO_UNIT, create_key_req.usage);
5962 ret = -EINVAL;
5963 return ret;
5964 }
5965
5966 ce_hw = kcalloc(entries, sizeof(*ce_hw), GFP_KERNEL);
5967 if (!ce_hw) {
5968 ret = -ENOMEM;
5969 return ret;
5970 }
5971 ret = __qseecom_get_ce_pipe_info(create_key_req.usage, &pipe, &ce_hw,
5972 DEFAULT_CE_INFO_UNIT);
5973 if (ret) {
5974 pr_err("Failed to retrieve pipe/ce_hw info: %d\n", ret);
5975 ret = -EINVAL;
5976 goto free_buf;
5977 }
5978
5979 if (qseecom.fde_key_size)
5980 flags |= QSEECOM_ICE_FDE_KEY_SIZE_32_BYTE;
5981 else
5982 flags |= QSEECOM_ICE_FDE_KEY_SIZE_16_BYTE;
5983
Jiten Patela7bb1d52018-05-11 12:34:26 +05305984 if (qseecom.enable_key_wrap_in_ks == true)
5985 flags |= ENABLE_KEY_WRAP_IN_KS;
5986
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07005987 generate_key_ireq.flags = flags;
5988 generate_key_ireq.qsee_command_id = QSEOS_GENERATE_KEY;
5989 memset((void *)generate_key_ireq.key_id,
5990 0, QSEECOM_KEY_ID_SIZE);
5991 memset((void *)generate_key_ireq.hash32,
5992 0, QSEECOM_HASH_SIZE);
5993 memcpy((void *)generate_key_ireq.key_id,
5994 (void *)key_id_array[create_key_req.usage].desc,
5995 QSEECOM_KEY_ID_SIZE);
5996 memcpy((void *)generate_key_ireq.hash32,
5997 (void *)create_key_req.hash32,
5998 QSEECOM_HASH_SIZE);
5999
6000 ret = __qseecom_generate_and_save_key(data,
6001 create_key_req.usage, &generate_key_ireq);
6002 if (ret) {
6003 pr_err("Failed to generate key on storage: %d\n", ret);
6004 goto free_buf;
6005 }
6006
6007 for (i = 0; i < entries; i++) {
6008 set_key_ireq.qsee_command_id = QSEOS_SET_KEY;
6009 if (create_key_req.usage ==
6010 QSEOS_KM_USAGE_UFS_ICE_DISK_ENCRYPTION) {
6011 set_key_ireq.ce = QSEECOM_UFS_ICE_CE_NUM;
6012 set_key_ireq.pipe = QSEECOM_ICE_FDE_KEY_INDEX;
6013
6014 } else if (create_key_req.usage ==
6015 QSEOS_KM_USAGE_SDCC_ICE_DISK_ENCRYPTION) {
6016 set_key_ireq.ce = QSEECOM_SDCC_ICE_CE_NUM;
6017 set_key_ireq.pipe = QSEECOM_ICE_FDE_KEY_INDEX;
6018
6019 } else {
6020 set_key_ireq.ce = ce_hw[i];
6021 set_key_ireq.pipe = pipe;
6022 }
6023 set_key_ireq.flags = flags;
6024
6025 /* set both PIPE_ENC and PIPE_ENC_XTS*/
6026 set_key_ireq.pipe_type = QSEOS_PIPE_ENC|QSEOS_PIPE_ENC_XTS;
6027 memset((void *)set_key_ireq.key_id, 0, QSEECOM_KEY_ID_SIZE);
6028 memset((void *)set_key_ireq.hash32, 0, QSEECOM_HASH_SIZE);
6029 memcpy((void *)set_key_ireq.key_id,
6030 (void *)key_id_array[create_key_req.usage].desc,
6031 QSEECOM_KEY_ID_SIZE);
6032 memcpy((void *)set_key_ireq.hash32,
6033 (void *)create_key_req.hash32,
6034 QSEECOM_HASH_SIZE);
6035 /*
6036 * It will return false if it is GPCE based crypto instance or
6037 * ICE is setup properly
6038 */
AnilKumar Chimata4e210f92017-04-28 14:31:25 -07006039 ret = qseecom_enable_ice_setup(create_key_req.usage);
6040 if (ret)
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07006041 goto free_buf;
6042
6043 do {
6044 ret = __qseecom_set_clear_ce_key(data,
6045 create_key_req.usage,
6046 &set_key_ireq);
6047 /*
6048 * wait a little before calling scm again to let other
6049 * processes run
6050 */
6051 if (ret == QSEOS_RESULT_FAIL_PENDING_OPERATION)
6052 msleep(50);
6053
6054 } while (ret == QSEOS_RESULT_FAIL_PENDING_OPERATION);
6055
6056 qseecom_disable_ice_setup(create_key_req.usage);
6057
6058 if (ret) {
6059 pr_err("Failed to create key: pipe %d, ce %d: %d\n",
6060 pipe, ce_hw[i], ret);
6061 goto free_buf;
6062 } else {
6063 pr_err("Set the key successfully\n");
6064 if ((create_key_req.usage ==
6065 QSEOS_KM_USAGE_UFS_ICE_DISK_ENCRYPTION) ||
6066 (create_key_req.usage ==
6067 QSEOS_KM_USAGE_SDCC_ICE_DISK_ENCRYPTION))
6068 goto free_buf;
6069 }
6070 }
6071
6072free_buf:
6073 kzfree(ce_hw);
6074 return ret;
6075}
6076
6077static int qseecom_wipe_key(struct qseecom_dev_handle *data,
6078 void __user *argp)
6079{
6080 uint32_t *ce_hw = NULL;
6081 uint32_t pipe = 0;
6082 int ret = 0;
6083 uint32_t flags = 0;
6084 int i, j;
6085 struct qseecom_wipe_key_req wipe_key_req;
6086 struct qseecom_key_delete_ireq delete_key_ireq;
6087 struct qseecom_key_select_ireq clear_key_ireq;
6088 uint32_t entries = 0;
6089
6090 ret = copy_from_user(&wipe_key_req, argp, sizeof(wipe_key_req));
6091 if (ret) {
6092 pr_err("copy_from_user failed\n");
6093 return ret;
6094 }
6095
6096 if (wipe_key_req.usage < QSEOS_KM_USAGE_DISK_ENCRYPTION ||
6097 wipe_key_req.usage >= QSEOS_KM_USAGE_MAX) {
6098 pr_err("unsupported usage %d\n", wipe_key_req.usage);
6099 ret = -EFAULT;
6100 return ret;
6101 }
6102
6103 entries = qseecom_get_ce_hw_instance(DEFAULT_CE_INFO_UNIT,
6104 wipe_key_req.usage);
6105 if (entries <= 0) {
6106 pr_err("no ce instance for usage %d instance %d\n",
6107 DEFAULT_CE_INFO_UNIT, wipe_key_req.usage);
6108 ret = -EINVAL;
6109 return ret;
6110 }
6111
6112 ce_hw = kcalloc(entries, sizeof(*ce_hw), GFP_KERNEL);
6113 if (!ce_hw) {
6114 ret = -ENOMEM;
6115 return ret;
6116 }
6117
6118 ret = __qseecom_get_ce_pipe_info(wipe_key_req.usage, &pipe, &ce_hw,
6119 DEFAULT_CE_INFO_UNIT);
6120 if (ret) {
6121 pr_err("Failed to retrieve pipe/ce_hw info: %d\n", ret);
6122 ret = -EINVAL;
6123 goto free_buf;
6124 }
6125
6126 if (wipe_key_req.wipe_key_flag) {
6127 delete_key_ireq.flags = flags;
6128 delete_key_ireq.qsee_command_id = QSEOS_DELETE_KEY;
6129 memset((void *)delete_key_ireq.key_id, 0, QSEECOM_KEY_ID_SIZE);
6130 memcpy((void *)delete_key_ireq.key_id,
6131 (void *)key_id_array[wipe_key_req.usage].desc,
6132 QSEECOM_KEY_ID_SIZE);
6133 memset((void *)delete_key_ireq.hash32, 0, QSEECOM_HASH_SIZE);
6134
6135 ret = __qseecom_delete_saved_key(data, wipe_key_req.usage,
6136 &delete_key_ireq);
6137 if (ret) {
6138 pr_err("Failed to delete key from ssd storage: %d\n",
6139 ret);
6140 ret = -EFAULT;
6141 goto free_buf;
6142 }
6143 }
6144
6145 for (j = 0; j < entries; j++) {
6146 clear_key_ireq.qsee_command_id = QSEOS_SET_KEY;
6147 if (wipe_key_req.usage ==
6148 QSEOS_KM_USAGE_UFS_ICE_DISK_ENCRYPTION) {
6149 clear_key_ireq.ce = QSEECOM_UFS_ICE_CE_NUM;
6150 clear_key_ireq.pipe = QSEECOM_ICE_FDE_KEY_INDEX;
6151 } else if (wipe_key_req.usage ==
6152 QSEOS_KM_USAGE_SDCC_ICE_DISK_ENCRYPTION) {
6153 clear_key_ireq.ce = QSEECOM_SDCC_ICE_CE_NUM;
6154 clear_key_ireq.pipe = QSEECOM_ICE_FDE_KEY_INDEX;
6155 } else {
6156 clear_key_ireq.ce = ce_hw[j];
6157 clear_key_ireq.pipe = pipe;
6158 }
6159 clear_key_ireq.flags = flags;
6160 clear_key_ireq.pipe_type = QSEOS_PIPE_ENC|QSEOS_PIPE_ENC_XTS;
6161 for (i = 0; i < QSEECOM_KEY_ID_SIZE; i++)
6162 clear_key_ireq.key_id[i] = QSEECOM_INVALID_KEY_ID;
6163 memset((void *)clear_key_ireq.hash32, 0, QSEECOM_HASH_SIZE);
6164
6165 /*
6166 * It will return false if it is GPCE based crypto instance or
6167 * ICE is setup properly
6168 */
AnilKumar Chimata4e210f92017-04-28 14:31:25 -07006169 ret = qseecom_enable_ice_setup(wipe_key_req.usage);
6170 if (ret)
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07006171 goto free_buf;
6172
6173 ret = __qseecom_set_clear_ce_key(data, wipe_key_req.usage,
6174 &clear_key_ireq);
6175
6176 qseecom_disable_ice_setup(wipe_key_req.usage);
6177
6178 if (ret) {
6179 pr_err("Failed to wipe key: pipe %d, ce %d: %d\n",
6180 pipe, ce_hw[j], ret);
6181 ret = -EFAULT;
6182 goto free_buf;
6183 }
6184 }
6185
6186free_buf:
6187 kzfree(ce_hw);
6188 return ret;
6189}
6190
6191static int qseecom_update_key_user_info(struct qseecom_dev_handle *data,
6192 void __user *argp)
6193{
6194 int ret = 0;
6195 uint32_t flags = 0;
6196 struct qseecom_update_key_userinfo_req update_key_req;
6197 struct qseecom_key_userinfo_update_ireq ireq;
6198
6199 ret = copy_from_user(&update_key_req, argp, sizeof(update_key_req));
6200 if (ret) {
6201 pr_err("copy_from_user failed\n");
6202 return ret;
6203 }
6204
6205 if (update_key_req.usage < QSEOS_KM_USAGE_DISK_ENCRYPTION ||
6206 update_key_req.usage >= QSEOS_KM_USAGE_MAX) {
6207 pr_err("Error:: unsupported usage %d\n", update_key_req.usage);
6208 return -EFAULT;
6209 }
6210
6211 ireq.qsee_command_id = QSEOS_UPDATE_KEY_USERINFO;
6212
6213 if (qseecom.fde_key_size)
6214 flags |= QSEECOM_ICE_FDE_KEY_SIZE_32_BYTE;
6215 else
6216 flags |= QSEECOM_ICE_FDE_KEY_SIZE_16_BYTE;
6217
6218 ireq.flags = flags;
6219 memset(ireq.key_id, 0, QSEECOM_KEY_ID_SIZE);
6220 memset((void *)ireq.current_hash32, 0, QSEECOM_HASH_SIZE);
6221 memset((void *)ireq.new_hash32, 0, QSEECOM_HASH_SIZE);
6222 memcpy((void *)ireq.key_id,
6223 (void *)key_id_array[update_key_req.usage].desc,
6224 QSEECOM_KEY_ID_SIZE);
6225 memcpy((void *)ireq.current_hash32,
6226 (void *)update_key_req.current_hash32, QSEECOM_HASH_SIZE);
6227 memcpy((void *)ireq.new_hash32,
6228 (void *)update_key_req.new_hash32, QSEECOM_HASH_SIZE);
6229
6230 do {
6231 ret = __qseecom_update_current_key_user_info(data,
6232 update_key_req.usage,
6233 &ireq);
6234 /*
6235 * wait a little before calling scm again to let other
6236 * processes run
6237 */
6238 if (ret == QSEOS_RESULT_FAIL_PENDING_OPERATION)
6239 msleep(50);
6240
6241 } while (ret == QSEOS_RESULT_FAIL_PENDING_OPERATION);
6242 if (ret) {
6243 pr_err("Failed to update key info: %d\n", ret);
6244 return ret;
6245 }
6246 return ret;
6247
6248}
6249static int qseecom_is_es_activated(void __user *argp)
6250{
Zhen Kong26e62742018-05-04 17:19:06 -07006251 struct qseecom_is_es_activated_req req = {0};
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07006252 struct qseecom_command_scm_resp resp;
6253 int ret;
6254
6255 if (qseecom.qsee_version < QSEE_VERSION_04) {
6256 pr_err("invalid qsee version\n");
6257 return -ENODEV;
6258 }
6259
6260 if (argp == NULL) {
6261 pr_err("arg is null\n");
6262 return -EINVAL;
6263 }
6264
6265 ret = qseecom_scm_call(SCM_SVC_ES, SCM_IS_ACTIVATED_ID,
6266 &req, sizeof(req), &resp, sizeof(resp));
6267 if (ret) {
6268 pr_err("scm_call failed\n");
6269 return ret;
6270 }
6271
6272 req.is_activated = resp.result;
6273 ret = copy_to_user(argp, &req, sizeof(req));
6274 if (ret) {
6275 pr_err("copy_to_user failed\n");
6276 return ret;
6277 }
6278
6279 return 0;
6280}
6281
6282static int qseecom_save_partition_hash(void __user *argp)
6283{
6284 struct qseecom_save_partition_hash_req req;
6285 struct qseecom_command_scm_resp resp;
6286 int ret;
6287
6288 memset(&resp, 0x00, sizeof(resp));
6289
6290 if (qseecom.qsee_version < QSEE_VERSION_04) {
6291 pr_err("invalid qsee version\n");
6292 return -ENODEV;
6293 }
6294
6295 if (argp == NULL) {
6296 pr_err("arg is null\n");
6297 return -EINVAL;
6298 }
6299
6300 ret = copy_from_user(&req, argp, sizeof(req));
6301 if (ret) {
6302 pr_err("copy_from_user failed\n");
6303 return ret;
6304 }
6305
6306 ret = qseecom_scm_call(SCM_SVC_ES, SCM_SAVE_PARTITION_HASH_ID,
6307 (void *)&req, sizeof(req), (void *)&resp, sizeof(resp));
6308 if (ret) {
6309 pr_err("qseecom_scm_call failed\n");
6310 return ret;
6311 }
6312
6313 return 0;
6314}
6315
6316static int qseecom_mdtp_cipher_dip(void __user *argp)
6317{
6318 struct qseecom_mdtp_cipher_dip_req req;
6319 u32 tzbuflenin, tzbuflenout;
6320 char *tzbufin = NULL, *tzbufout = NULL;
6321 struct scm_desc desc = {0};
6322 int ret;
6323
6324 do {
6325 /* Copy the parameters from userspace */
6326 if (argp == NULL) {
6327 pr_err("arg is null\n");
6328 ret = -EINVAL;
6329 break;
6330 }
6331
6332 ret = copy_from_user(&req, argp, sizeof(req));
6333 if (ret) {
6334 pr_err("copy_from_user failed, ret= %d\n", ret);
6335 break;
6336 }
6337
6338 if (req.in_buf == NULL || req.out_buf == NULL ||
6339 req.in_buf_size == 0 || req.in_buf_size > MAX_DIP ||
6340 req.out_buf_size == 0 || req.out_buf_size > MAX_DIP ||
6341 req.direction > 1) {
6342 pr_err("invalid parameters\n");
6343 ret = -EINVAL;
6344 break;
6345 }
6346
6347 /* Copy the input buffer from userspace to kernel space */
6348 tzbuflenin = PAGE_ALIGN(req.in_buf_size);
6349 tzbufin = kzalloc(tzbuflenin, GFP_KERNEL);
6350 if (!tzbufin) {
6351 pr_err("error allocating in buffer\n");
6352 ret = -ENOMEM;
6353 break;
6354 }
6355
6356 ret = copy_from_user(tzbufin, req.in_buf, req.in_buf_size);
6357 if (ret) {
6358 pr_err("copy_from_user failed, ret=%d\n", ret);
6359 break;
6360 }
6361
6362 dmac_flush_range(tzbufin, tzbufin + tzbuflenin);
6363
6364 /* Prepare the output buffer in kernel space */
6365 tzbuflenout = PAGE_ALIGN(req.out_buf_size);
6366 tzbufout = kzalloc(tzbuflenout, GFP_KERNEL);
6367 if (!tzbufout) {
6368 pr_err("error allocating out buffer\n");
6369 ret = -ENOMEM;
6370 break;
6371 }
6372
6373 dmac_flush_range(tzbufout, tzbufout + tzbuflenout);
6374
6375 /* Send the command to TZ */
6376 desc.arginfo = TZ_MDTP_CIPHER_DIP_ID_PARAM_ID;
6377 desc.args[0] = virt_to_phys(tzbufin);
6378 desc.args[1] = req.in_buf_size;
6379 desc.args[2] = virt_to_phys(tzbufout);
6380 desc.args[3] = req.out_buf_size;
6381 desc.args[4] = req.direction;
6382
6383 ret = __qseecom_enable_clk(CLK_QSEE);
6384 if (ret)
6385 break;
6386
6387 ret = scm_call2(TZ_MDTP_CIPHER_DIP_ID, &desc);
6388
6389 __qseecom_disable_clk(CLK_QSEE);
6390
6391 if (ret) {
6392 pr_err("scm_call2 failed for SCM_SVC_MDTP, ret=%d\n",
6393 ret);
6394 break;
6395 }
6396
6397 /* Copy the output buffer from kernel space to userspace */
6398 dmac_flush_range(tzbufout, tzbufout + tzbuflenout);
6399 ret = copy_to_user(req.out_buf, tzbufout, req.out_buf_size);
6400 if (ret) {
6401 pr_err("copy_to_user failed, ret=%d\n", ret);
6402 break;
6403 }
6404 } while (0);
6405
6406 kzfree(tzbufin);
6407 kzfree(tzbufout);
6408
6409 return ret;
6410}
6411
6412static int __qseecom_qteec_validate_msg(struct qseecom_dev_handle *data,
6413 struct qseecom_qteec_req *req)
6414{
6415 if (!data || !data->client.ihandle) {
6416 pr_err("Client or client handle is not initialized\n");
6417 return -EINVAL;
6418 }
6419
6420 if (data->type != QSEECOM_CLIENT_APP)
6421 return -EFAULT;
6422
6423 if (req->req_len > UINT_MAX - req->resp_len) {
6424 pr_err("Integer overflow detected in req_len & rsp_len\n");
6425 return -EINVAL;
6426 }
6427
6428 if (req->req_len + req->resp_len > data->client.sb_length) {
6429 pr_debug("Not enough memory to fit cmd_buf.\n");
6430 pr_debug("resp_buf. Required: %u, Available: %zu\n",
6431 (req->req_len + req->resp_len), data->client.sb_length);
6432 return -ENOMEM;
6433 }
6434
6435 if (req->req_ptr == NULL || req->resp_ptr == NULL) {
6436 pr_err("cmd buffer or response buffer is null\n");
6437 return -EINVAL;
6438 }
6439 if (((uintptr_t)req->req_ptr <
6440 data->client.user_virt_sb_base) ||
6441 ((uintptr_t)req->req_ptr >=
6442 (data->client.user_virt_sb_base + data->client.sb_length))) {
6443 pr_err("cmd buffer address not within shared bufffer\n");
6444 return -EINVAL;
6445 }
6446
6447 if (((uintptr_t)req->resp_ptr <
6448 data->client.user_virt_sb_base) ||
6449 ((uintptr_t)req->resp_ptr >=
6450 (data->client.user_virt_sb_base + data->client.sb_length))) {
6451 pr_err("response buffer address not within shared bufffer\n");
6452 return -EINVAL;
6453 }
6454
6455 if ((req->req_len == 0) || (req->resp_len == 0)) {
6456 pr_err("cmd buf lengtgh/response buf length not valid\n");
6457 return -EINVAL;
6458 }
6459
6460 if ((uintptr_t)req->req_ptr > (ULONG_MAX - req->req_len)) {
6461 pr_err("Integer overflow in req_len & req_ptr\n");
6462 return -EINVAL;
6463 }
6464
6465 if ((uintptr_t)req->resp_ptr > (ULONG_MAX - req->resp_len)) {
6466 pr_err("Integer overflow in resp_len & resp_ptr\n");
6467 return -EINVAL;
6468 }
6469
6470 if (data->client.user_virt_sb_base >
6471 (ULONG_MAX - data->client.sb_length)) {
6472 pr_err("Integer overflow in user_virt_sb_base & sb_length\n");
6473 return -EINVAL;
6474 }
6475 if ((((uintptr_t)req->req_ptr + req->req_len) >
6476 ((uintptr_t)data->client.user_virt_sb_base +
6477 data->client.sb_length)) ||
6478 (((uintptr_t)req->resp_ptr + req->resp_len) >
6479 ((uintptr_t)data->client.user_virt_sb_base +
6480 data->client.sb_length))) {
6481 pr_err("cmd buf or resp buf is out of shared buffer region\n");
6482 return -EINVAL;
6483 }
6484 return 0;
6485}
6486
6487static int __qseecom_qteec_handle_pre_alc_fd(struct qseecom_dev_handle *data,
6488 uint32_t fd_idx, struct sg_table *sg_ptr)
6489{
6490 struct scatterlist *sg = sg_ptr->sgl;
6491 struct qseecom_sg_entry *sg_entry;
6492 void *buf;
6493 uint i;
6494 size_t size;
6495 dma_addr_t coh_pmem;
6496
6497 if (fd_idx >= MAX_ION_FD) {
6498 pr_err("fd_idx [%d] is invalid\n", fd_idx);
6499 return -ENOMEM;
6500 }
6501 /*
6502 * Allocate a buffer, populate it with number of entry plus
6503 * each sg entry's phy addr and length; then return the
6504 * phy_addr of the buffer.
6505 */
6506 size = sizeof(uint32_t) +
6507 sizeof(struct qseecom_sg_entry) * sg_ptr->nents;
6508 size = (size + PAGE_SIZE) & PAGE_MASK;
6509 buf = dma_alloc_coherent(qseecom.pdev,
6510 size, &coh_pmem, GFP_KERNEL);
6511 if (buf == NULL) {
6512 pr_err("failed to alloc memory for sg buf\n");
6513 return -ENOMEM;
6514 }
6515 *(uint32_t *)buf = sg_ptr->nents;
6516 sg_entry = (struct qseecom_sg_entry *) (buf + sizeof(uint32_t));
6517 for (i = 0; i < sg_ptr->nents; i++) {
6518 sg_entry->phys_addr = (uint32_t)sg_dma_address(sg);
6519 sg_entry->len = sg->length;
6520 sg_entry++;
6521 sg = sg_next(sg);
6522 }
6523 data->client.sec_buf_fd[fd_idx].is_sec_buf_fd = true;
6524 data->client.sec_buf_fd[fd_idx].vbase = buf;
6525 data->client.sec_buf_fd[fd_idx].pbase = coh_pmem;
6526 data->client.sec_buf_fd[fd_idx].size = size;
6527 return 0;
6528}
6529
6530static int __qseecom_update_qteec_req_buf(struct qseecom_qteec_modfd_req *req,
6531 struct qseecom_dev_handle *data, bool cleanup)
6532{
6533 struct ion_handle *ihandle;
6534 int ret = 0;
6535 int i = 0;
6536 uint32_t *update;
6537 struct sg_table *sg_ptr = NULL;
6538 struct scatterlist *sg;
6539 struct qseecom_param_memref *memref;
6540
6541 if (req == NULL) {
6542 pr_err("Invalid address\n");
6543 return -EINVAL;
6544 }
6545 for (i = 0; i < MAX_ION_FD; i++) {
6546 if (req->ifd_data[i].fd > 0) {
AnilKumar Chimata04d60cf2017-04-09 11:43:10 -07006547 ihandle = ion_import_dma_buf_fd(qseecom.ion_clnt,
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07006548 req->ifd_data[i].fd);
6549 if (IS_ERR_OR_NULL(ihandle)) {
6550 pr_err("Ion client can't retrieve the handle\n");
6551 return -ENOMEM;
6552 }
6553 if ((req->req_len < sizeof(uint32_t)) ||
6554 (req->ifd_data[i].cmd_buf_offset >
6555 req->req_len - sizeof(uint32_t))) {
6556 pr_err("Invalid offset/req len 0x%x/0x%x\n",
6557 req->req_len,
6558 req->ifd_data[i].cmd_buf_offset);
6559 return -EINVAL;
6560 }
6561 update = (uint32_t *)((char *) req->req_ptr +
6562 req->ifd_data[i].cmd_buf_offset);
6563 if (!update) {
6564 pr_err("update pointer is NULL\n");
6565 return -EINVAL;
6566 }
6567 } else {
6568 continue;
6569 }
6570 /* Populate the cmd data structure with the phys_addr */
6571 sg_ptr = ion_sg_table(qseecom.ion_clnt, ihandle);
6572 if (IS_ERR_OR_NULL(sg_ptr)) {
6573 pr_err("IOn client could not retrieve sg table\n");
6574 goto err;
6575 }
6576 sg = sg_ptr->sgl;
6577 if (sg == NULL) {
6578 pr_err("sg is NULL\n");
6579 goto err;
6580 }
6581 if ((sg_ptr->nents == 0) || (sg->length == 0)) {
6582 pr_err("Num of scat entr (%d)or length(%d) invalid\n",
6583 sg_ptr->nents, sg->length);
6584 goto err;
6585 }
6586 /* clean up buf for pre-allocated fd */
6587 if (cleanup && data->client.sec_buf_fd[i].is_sec_buf_fd &&
6588 (*update)) {
6589 if (data->client.sec_buf_fd[i].vbase)
6590 dma_free_coherent(qseecom.pdev,
6591 data->client.sec_buf_fd[i].size,
6592 data->client.sec_buf_fd[i].vbase,
6593 data->client.sec_buf_fd[i].pbase);
6594 memset((void *)update, 0,
6595 sizeof(struct qseecom_param_memref));
6596 memset(&(data->client.sec_buf_fd[i]), 0,
6597 sizeof(struct qseecom_sec_buf_fd_info));
6598 goto clean;
6599 }
6600
6601 if (*update == 0) {
6602 /* update buf for pre-allocated fd from secure heap*/
6603 ret = __qseecom_qteec_handle_pre_alc_fd(data, i,
6604 sg_ptr);
6605 if (ret) {
6606 pr_err("Failed to handle buf for fd[%d]\n", i);
6607 goto err;
6608 }
6609 memref = (struct qseecom_param_memref *)update;
6610 memref->buffer =
6611 (uint32_t)(data->client.sec_buf_fd[i].pbase);
6612 memref->size =
6613 (uint32_t)(data->client.sec_buf_fd[i].size);
6614 } else {
6615 /* update buf for fd from non-secure qseecom heap */
6616 if (sg_ptr->nents != 1) {
6617 pr_err("Num of scat entr (%d) invalid\n",
6618 sg_ptr->nents);
6619 goto err;
6620 }
6621 if (cleanup)
6622 *update = 0;
6623 else
6624 *update = (uint32_t)sg_dma_address(sg_ptr->sgl);
6625 }
6626clean:
6627 if (cleanup) {
6628 ret = msm_ion_do_cache_op(qseecom.ion_clnt,
6629 ihandle, NULL, sg->length,
6630 ION_IOC_INV_CACHES);
6631 if (ret) {
6632 pr_err("cache operation failed %d\n", ret);
6633 goto err;
6634 }
6635 } else {
6636 ret = msm_ion_do_cache_op(qseecom.ion_clnt,
6637 ihandle, NULL, sg->length,
6638 ION_IOC_CLEAN_INV_CACHES);
6639 if (ret) {
6640 pr_err("cache operation failed %d\n", ret);
6641 goto err;
6642 }
6643 data->sglistinfo_ptr[i].indexAndFlags =
6644 SGLISTINFO_SET_INDEX_FLAG(
6645 (sg_ptr->nents == 1), 0,
6646 req->ifd_data[i].cmd_buf_offset);
6647 data->sglistinfo_ptr[i].sizeOrCount =
6648 (sg_ptr->nents == 1) ?
6649 sg->length : sg_ptr->nents;
6650 data->sglist_cnt = i + 1;
6651 }
6652 /* Deallocate the handle */
6653 if (!IS_ERR_OR_NULL(ihandle))
6654 ion_free(qseecom.ion_clnt, ihandle);
6655 }
6656 return ret;
6657err:
6658 if (!IS_ERR_OR_NULL(ihandle))
6659 ion_free(qseecom.ion_clnt, ihandle);
6660 return -ENOMEM;
6661}
6662
6663static int __qseecom_qteec_issue_cmd(struct qseecom_dev_handle *data,
6664 struct qseecom_qteec_req *req, uint32_t cmd_id)
6665{
6666 struct qseecom_command_scm_resp resp;
6667 struct qseecom_qteec_ireq ireq;
6668 struct qseecom_qteec_64bit_ireq ireq_64bit;
6669 struct qseecom_registered_app_list *ptr_app;
6670 bool found_app = false;
6671 unsigned long flags;
6672 int ret = 0;
Zhen Kong4af480e2017-09-19 14:34:16 -07006673 int ret2 = 0;
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07006674 uint32_t reqd_len_sb_in = 0;
6675 void *cmd_buf = NULL;
6676 size_t cmd_len;
6677 struct sglist_info *table = data->sglistinfo_ptr;
Brahmaji Kb33e26e2017-06-01 17:20:10 +05306678 void *req_ptr = NULL;
6679 void *resp_ptr = NULL;
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07006680
6681 ret = __qseecom_qteec_validate_msg(data, req);
6682 if (ret)
6683 return ret;
6684
Brahmaji Kb33e26e2017-06-01 17:20:10 +05306685 req_ptr = req->req_ptr;
6686 resp_ptr = req->resp_ptr;
6687
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07006688 /* find app_id & img_name from list */
6689 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
6690 list_for_each_entry(ptr_app, &qseecom.registered_app_list_head,
6691 list) {
6692 if ((ptr_app->app_id == data->client.app_id) &&
6693 (!strcmp(ptr_app->app_name, data->client.app_name))) {
6694 found_app = true;
6695 break;
6696 }
6697 }
6698 spin_unlock_irqrestore(&qseecom.registered_app_list_lock, flags);
6699 if (!found_app) {
6700 pr_err("app_id %d (%s) is not found\n", data->client.app_id,
6701 (char *)data->client.app_name);
6702 return -ENOENT;
6703 }
6704
Brahmaji Kb33e26e2017-06-01 17:20:10 +05306705 req->req_ptr = (void *)__qseecom_uvirt_to_kvirt(data,
6706 (uintptr_t)req->req_ptr);
6707 req->resp_ptr = (void *)__qseecom_uvirt_to_kvirt(data,
6708 (uintptr_t)req->resp_ptr);
6709
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07006710 if ((cmd_id == QSEOS_TEE_OPEN_SESSION) ||
6711 (cmd_id == QSEOS_TEE_REQUEST_CANCELLATION)) {
6712 ret = __qseecom_update_qteec_req_buf(
6713 (struct qseecom_qteec_modfd_req *)req, data, false);
6714 if (ret)
6715 return ret;
6716 }
6717
6718 if (qseecom.qsee_version < QSEE_VERSION_40) {
6719 ireq.app_id = data->client.app_id;
6720 ireq.req_ptr = (uint32_t)__qseecom_uvirt_to_kphys(data,
Brahmaji Kb33e26e2017-06-01 17:20:10 +05306721 (uintptr_t)req_ptr);
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07006722 ireq.req_len = req->req_len;
6723 ireq.resp_ptr = (uint32_t)__qseecom_uvirt_to_kphys(data,
Brahmaji Kb33e26e2017-06-01 17:20:10 +05306724 (uintptr_t)resp_ptr);
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07006725 ireq.resp_len = req->resp_len;
6726 ireq.sglistinfo_ptr = (uint32_t)virt_to_phys(table);
6727 ireq.sglistinfo_len = SGLISTINFO_TABLE_SIZE;
6728 dmac_flush_range((void *)table,
6729 (void *)table + SGLISTINFO_TABLE_SIZE);
6730 cmd_buf = (void *)&ireq;
6731 cmd_len = sizeof(struct qseecom_qteec_ireq);
6732 } else {
6733 ireq_64bit.app_id = data->client.app_id;
6734 ireq_64bit.req_ptr = (uint64_t)__qseecom_uvirt_to_kphys(data,
Brahmaji Kb33e26e2017-06-01 17:20:10 +05306735 (uintptr_t)req_ptr);
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07006736 ireq_64bit.req_len = req->req_len;
6737 ireq_64bit.resp_ptr = (uint64_t)__qseecom_uvirt_to_kphys(data,
Brahmaji Kb33e26e2017-06-01 17:20:10 +05306738 (uintptr_t)resp_ptr);
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07006739 ireq_64bit.resp_len = req->resp_len;
6740 if ((data->client.app_arch == ELFCLASS32) &&
6741 ((ireq_64bit.req_ptr >=
6742 PHY_ADDR_4G - ireq_64bit.req_len) ||
6743 (ireq_64bit.resp_ptr >=
6744 PHY_ADDR_4G - ireq_64bit.resp_len))){
6745 pr_err("32bit app %s (id: %d): phy_addr exceeds 4G\n",
6746 data->client.app_name, data->client.app_id);
6747 pr_err("req_ptr:%llx,req_len:%x,rsp_ptr:%llx,rsp_len:%x\n",
6748 ireq_64bit.req_ptr, ireq_64bit.req_len,
6749 ireq_64bit.resp_ptr, ireq_64bit.resp_len);
6750 return -EFAULT;
6751 }
6752 ireq_64bit.sglistinfo_ptr = (uint64_t)virt_to_phys(table);
6753 ireq_64bit.sglistinfo_len = SGLISTINFO_TABLE_SIZE;
6754 dmac_flush_range((void *)table,
6755 (void *)table + SGLISTINFO_TABLE_SIZE);
6756 cmd_buf = (void *)&ireq_64bit;
6757 cmd_len = sizeof(struct qseecom_qteec_64bit_ireq);
6758 }
6759 if (qseecom.whitelist_support == true
6760 && cmd_id == QSEOS_TEE_OPEN_SESSION)
6761 *(uint32_t *)cmd_buf = QSEOS_TEE_OPEN_SESSION_WHITELIST;
6762 else
6763 *(uint32_t *)cmd_buf = cmd_id;
6764
6765 reqd_len_sb_in = req->req_len + req->resp_len;
6766 ret = msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
6767 data->client.sb_virt,
6768 reqd_len_sb_in,
6769 ION_IOC_CLEAN_INV_CACHES);
6770 if (ret) {
6771 pr_err("cache operation failed %d\n", ret);
6772 return ret;
6773 }
6774
6775 __qseecom_reentrancy_check_if_this_app_blocked(ptr_app);
6776
6777 ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1,
6778 cmd_buf, cmd_len,
6779 &resp, sizeof(resp));
6780 if (ret) {
6781 pr_err("scm_call() failed with err: %d (app_id = %d)\n",
6782 ret, data->client.app_id);
Zhen Kong4af480e2017-09-19 14:34:16 -07006783 goto exit;
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07006784 }
6785
6786 if (qseecom.qsee_reentrancy_support) {
6787 ret = __qseecom_process_reentrancy(&resp, ptr_app, data);
Zhen Kong4af480e2017-09-19 14:34:16 -07006788 if (ret)
6789 goto exit;
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07006790 } else {
6791 if (resp.result == QSEOS_RESULT_INCOMPLETE) {
6792 ret = __qseecom_process_incomplete_cmd(data, &resp);
6793 if (ret) {
6794 pr_err("process_incomplete_cmd failed err: %d\n",
6795 ret);
Zhen Kong4af480e2017-09-19 14:34:16 -07006796 goto exit;
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07006797 }
6798 } else {
6799 if (resp.result != QSEOS_RESULT_SUCCESS) {
6800 pr_err("Response result %d not supported\n",
6801 resp.result);
6802 ret = -EINVAL;
Zhen Kong4af480e2017-09-19 14:34:16 -07006803 goto exit;
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07006804 }
6805 }
6806 }
Zhen Kong4af480e2017-09-19 14:34:16 -07006807exit:
6808 ret2 = msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07006809 data->client.sb_virt, data->client.sb_length,
6810 ION_IOC_INV_CACHES);
Zhen Kong4af480e2017-09-19 14:34:16 -07006811 if (ret2) {
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07006812 pr_err("cache operation failed %d\n", ret);
Zhen Kong4af480e2017-09-19 14:34:16 -07006813 return ret2;
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07006814 }
6815
6816 if ((cmd_id == QSEOS_TEE_OPEN_SESSION) ||
6817 (cmd_id == QSEOS_TEE_REQUEST_CANCELLATION)) {
Zhen Kong4af480e2017-09-19 14:34:16 -07006818 ret2 = __qseecom_update_qteec_req_buf(
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07006819 (struct qseecom_qteec_modfd_req *)req, data, true);
Zhen Kong4af480e2017-09-19 14:34:16 -07006820 if (ret2)
6821 return ret2;
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07006822 }
Zhen Kong4af480e2017-09-19 14:34:16 -07006823 return ret;
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07006824}
6825
6826static int qseecom_qteec_open_session(struct qseecom_dev_handle *data,
6827 void __user *argp)
6828{
6829 struct qseecom_qteec_modfd_req req;
6830 int ret = 0;
6831
6832 ret = copy_from_user(&req, argp,
6833 sizeof(struct qseecom_qteec_modfd_req));
6834 if (ret) {
6835 pr_err("copy_from_user failed\n");
6836 return ret;
6837 }
6838 ret = __qseecom_qteec_issue_cmd(data, (struct qseecom_qteec_req *)&req,
6839 QSEOS_TEE_OPEN_SESSION);
6840
6841 return ret;
6842}
6843
6844static int qseecom_qteec_close_session(struct qseecom_dev_handle *data,
6845 void __user *argp)
6846{
6847 struct qseecom_qteec_req req;
6848 int ret = 0;
6849
6850 ret = copy_from_user(&req, argp, sizeof(struct qseecom_qteec_req));
6851 if (ret) {
6852 pr_err("copy_from_user failed\n");
6853 return ret;
6854 }
6855 ret = __qseecom_qteec_issue_cmd(data, &req, QSEOS_TEE_CLOSE_SESSION);
6856 return ret;
6857}
6858
6859static int qseecom_qteec_invoke_modfd_cmd(struct qseecom_dev_handle *data,
6860 void __user *argp)
6861{
6862 struct qseecom_qteec_modfd_req req;
6863 struct qseecom_command_scm_resp resp;
6864 struct qseecom_qteec_ireq ireq;
6865 struct qseecom_qteec_64bit_ireq ireq_64bit;
6866 struct qseecom_registered_app_list *ptr_app;
6867 bool found_app = false;
6868 unsigned long flags;
6869 int ret = 0;
6870 int i = 0;
6871 uint32_t reqd_len_sb_in = 0;
6872 void *cmd_buf = NULL;
6873 size_t cmd_len;
6874 struct sglist_info *table = data->sglistinfo_ptr;
6875 void *req_ptr = NULL;
6876 void *resp_ptr = NULL;
6877
6878 ret = copy_from_user(&req, argp,
6879 sizeof(struct qseecom_qteec_modfd_req));
6880 if (ret) {
6881 pr_err("copy_from_user failed\n");
6882 return ret;
6883 }
6884 ret = __qseecom_qteec_validate_msg(data,
6885 (struct qseecom_qteec_req *)(&req));
6886 if (ret)
6887 return ret;
6888 req_ptr = req.req_ptr;
6889 resp_ptr = req.resp_ptr;
6890
6891 /* find app_id & img_name from list */
6892 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
6893 list_for_each_entry(ptr_app, &qseecom.registered_app_list_head,
6894 list) {
6895 if ((ptr_app->app_id == data->client.app_id) &&
6896 (!strcmp(ptr_app->app_name, data->client.app_name))) {
6897 found_app = true;
6898 break;
6899 }
6900 }
6901 spin_unlock_irqrestore(&qseecom.registered_app_list_lock, flags);
6902 if (!found_app) {
6903 pr_err("app_id %d (%s) is not found\n", data->client.app_id,
6904 (char *)data->client.app_name);
6905 return -ENOENT;
6906 }
6907
6908 /* validate offsets */
6909 for (i = 0; i < MAX_ION_FD; i++) {
6910 if (req.ifd_data[i].fd) {
6911 if (req.ifd_data[i].cmd_buf_offset >= req.req_len)
6912 return -EINVAL;
6913 }
6914 }
6915 req.req_ptr = (void *)__qseecom_uvirt_to_kvirt(data,
6916 (uintptr_t)req.req_ptr);
6917 req.resp_ptr = (void *)__qseecom_uvirt_to_kvirt(data,
6918 (uintptr_t)req.resp_ptr);
6919 ret = __qseecom_update_qteec_req_buf(&req, data, false);
6920 if (ret)
6921 return ret;
6922
6923 if (qseecom.qsee_version < QSEE_VERSION_40) {
6924 ireq.app_id = data->client.app_id;
6925 ireq.req_ptr = (uint32_t)__qseecom_uvirt_to_kphys(data,
6926 (uintptr_t)req_ptr);
6927 ireq.req_len = req.req_len;
6928 ireq.resp_ptr = (uint32_t)__qseecom_uvirt_to_kphys(data,
6929 (uintptr_t)resp_ptr);
6930 ireq.resp_len = req.resp_len;
6931 cmd_buf = (void *)&ireq;
6932 cmd_len = sizeof(struct qseecom_qteec_ireq);
6933 ireq.sglistinfo_ptr = (uint32_t)virt_to_phys(table);
6934 ireq.sglistinfo_len = SGLISTINFO_TABLE_SIZE;
6935 dmac_flush_range((void *)table,
6936 (void *)table + SGLISTINFO_TABLE_SIZE);
6937 } else {
6938 ireq_64bit.app_id = data->client.app_id;
6939 ireq_64bit.req_ptr = (uint64_t)__qseecom_uvirt_to_kphys(data,
6940 (uintptr_t)req_ptr);
6941 ireq_64bit.req_len = req.req_len;
6942 ireq_64bit.resp_ptr = (uint64_t)__qseecom_uvirt_to_kphys(data,
6943 (uintptr_t)resp_ptr);
6944 ireq_64bit.resp_len = req.resp_len;
6945 cmd_buf = (void *)&ireq_64bit;
6946 cmd_len = sizeof(struct qseecom_qteec_64bit_ireq);
6947 ireq_64bit.sglistinfo_ptr = (uint64_t)virt_to_phys(table);
6948 ireq_64bit.sglistinfo_len = SGLISTINFO_TABLE_SIZE;
6949 dmac_flush_range((void *)table,
6950 (void *)table + SGLISTINFO_TABLE_SIZE);
6951 }
6952 reqd_len_sb_in = req.req_len + req.resp_len;
6953 if (qseecom.whitelist_support == true)
6954 *(uint32_t *)cmd_buf = QSEOS_TEE_INVOKE_COMMAND_WHITELIST;
6955 else
6956 *(uint32_t *)cmd_buf = QSEOS_TEE_INVOKE_COMMAND;
6957
6958 ret = msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
6959 data->client.sb_virt,
6960 reqd_len_sb_in,
6961 ION_IOC_CLEAN_INV_CACHES);
6962 if (ret) {
6963 pr_err("cache operation failed %d\n", ret);
6964 return ret;
6965 }
6966
6967 __qseecom_reentrancy_check_if_this_app_blocked(ptr_app);
6968
6969 ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1,
6970 cmd_buf, cmd_len,
6971 &resp, sizeof(resp));
6972 if (ret) {
6973 pr_err("scm_call() failed with err: %d (app_id = %d)\n",
6974 ret, data->client.app_id);
6975 return ret;
6976 }
6977
6978 if (qseecom.qsee_reentrancy_support) {
6979 ret = __qseecom_process_reentrancy(&resp, ptr_app, data);
6980 } else {
6981 if (resp.result == QSEOS_RESULT_INCOMPLETE) {
6982 ret = __qseecom_process_incomplete_cmd(data, &resp);
6983 if (ret) {
6984 pr_err("process_incomplete_cmd failed err: %d\n",
6985 ret);
6986 return ret;
6987 }
6988 } else {
6989 if (resp.result != QSEOS_RESULT_SUCCESS) {
6990 pr_err("Response result %d not supported\n",
6991 resp.result);
6992 ret = -EINVAL;
6993 }
6994 }
6995 }
6996 ret = __qseecom_update_qteec_req_buf(&req, data, true);
6997 if (ret)
6998 return ret;
6999
7000 ret = msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
7001 data->client.sb_virt, data->client.sb_length,
7002 ION_IOC_INV_CACHES);
7003 if (ret) {
7004 pr_err("cache operation failed %d\n", ret);
7005 return ret;
7006 }
7007 return 0;
7008}
7009
7010static int qseecom_qteec_request_cancellation(struct qseecom_dev_handle *data,
7011 void __user *argp)
7012{
7013 struct qseecom_qteec_modfd_req req;
7014 int ret = 0;
7015
7016 ret = copy_from_user(&req, argp,
7017 sizeof(struct qseecom_qteec_modfd_req));
7018 if (ret) {
7019 pr_err("copy_from_user failed\n");
7020 return ret;
7021 }
7022 ret = __qseecom_qteec_issue_cmd(data, (struct qseecom_qteec_req *)&req,
7023 QSEOS_TEE_REQUEST_CANCELLATION);
7024
7025 return ret;
7026}
7027
7028static void __qseecom_clean_data_sglistinfo(struct qseecom_dev_handle *data)
7029{
7030 if (data->sglist_cnt) {
7031 memset(data->sglistinfo_ptr, 0,
7032 SGLISTINFO_TABLE_SIZE);
7033 data->sglist_cnt = 0;
7034 }
7035}
7036
7037static inline long qseecom_ioctl(struct file *file,
7038 unsigned int cmd, unsigned long arg)
7039{
7040 int ret = 0;
7041 struct qseecom_dev_handle *data = file->private_data;
7042 void __user *argp = (void __user *) arg;
7043 bool perf_enabled = false;
7044
7045 if (!data) {
7046 pr_err("Invalid/uninitialized device handle\n");
7047 return -EINVAL;
7048 }
7049
7050 if (data->abort) {
7051 pr_err("Aborting qseecom driver\n");
7052 return -ENODEV;
7053 }
Zhen Kongbcdeda22018-11-16 13:50:51 -08007054 if (cmd != QSEECOM_IOCTL_RECEIVE_REQ &&
7055 cmd != QSEECOM_IOCTL_SEND_RESP_REQ &&
7056 cmd != QSEECOM_IOCTL_SEND_MODFD_RESP &&
7057 cmd != QSEECOM_IOCTL_SEND_MODFD_RESP_64)
7058 __qseecom_processing_pending_lsnr_unregister();
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07007059
7060 switch (cmd) {
7061 case QSEECOM_IOCTL_REGISTER_LISTENER_REQ: {
7062 if (data->type != QSEECOM_GENERIC) {
7063 pr_err("reg lstnr req: invalid handle (%d)\n",
7064 data->type);
7065 ret = -EINVAL;
7066 break;
7067 }
7068 pr_debug("ioctl register_listener_req()\n");
Zhen Kongbcdeda22018-11-16 13:50:51 -08007069 mutex_lock(&listener_access_lock);
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07007070 atomic_inc(&data->ioctl_count);
7071 data->type = QSEECOM_LISTENER_SERVICE;
7072 ret = qseecom_register_listener(data, argp);
7073 atomic_dec(&data->ioctl_count);
7074 wake_up_all(&data->abort_wq);
Zhen Kongbcdeda22018-11-16 13:50:51 -08007075 mutex_unlock(&listener_access_lock);
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07007076 if (ret)
7077 pr_err("failed qseecom_register_listener: %d\n", ret);
7078 break;
7079 }
Neeraj Sonib30ac1f2018-04-17 14:48:42 +05307080 case QSEECOM_IOCTL_SET_ICE_INFO: {
7081 struct qseecom_ice_data_t ice_data;
7082
7083 ret = copy_from_user(&ice_data, argp, sizeof(ice_data));
7084 if (ret) {
7085 pr_err("copy_from_user failed\n");
7086 return -EFAULT;
7087 }
7088 qcom_ice_set_fde_flag(ice_data.flag);
7089 break;
7090 }
7091
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07007092 case QSEECOM_IOCTL_UNREGISTER_LISTENER_REQ: {
7093 if ((data->listener.id == 0) ||
7094 (data->type != QSEECOM_LISTENER_SERVICE)) {
7095 pr_err("unreg lstnr req: invalid handle (%d) lid(%d)\n",
7096 data->type, data->listener.id);
7097 ret = -EINVAL;
7098 break;
7099 }
7100 pr_debug("ioctl unregister_listener_req()\n");
Zhen Kongbcdeda22018-11-16 13:50:51 -08007101 mutex_lock(&listener_access_lock);
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07007102 atomic_inc(&data->ioctl_count);
7103 ret = qseecom_unregister_listener(data);
7104 atomic_dec(&data->ioctl_count);
7105 wake_up_all(&data->abort_wq);
Zhen Kongbcdeda22018-11-16 13:50:51 -08007106 mutex_unlock(&listener_access_lock);
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07007107 if (ret)
7108 pr_err("failed qseecom_unregister_listener: %d\n", ret);
7109 break;
7110 }
7111 case QSEECOM_IOCTL_SEND_CMD_REQ: {
7112 if ((data->client.app_id == 0) ||
7113 (data->type != QSEECOM_CLIENT_APP)) {
7114 pr_err("send cmd req: invalid handle (%d) app_id(%d)\n",
7115 data->type, data->client.app_id);
7116 ret = -EINVAL;
7117 break;
7118 }
7119 /* Only one client allowed here at a time */
7120 mutex_lock(&app_access_lock);
7121 if (qseecom.support_bus_scaling) {
7122 /* register bus bw in case the client doesn't do it */
7123 if (!data->mode) {
7124 mutex_lock(&qsee_bw_mutex);
7125 __qseecom_register_bus_bandwidth_needs(
7126 data, HIGH);
7127 mutex_unlock(&qsee_bw_mutex);
7128 }
7129 ret = qseecom_scale_bus_bandwidth_timer(INACTIVE);
7130 if (ret) {
7131 pr_err("Failed to set bw.\n");
7132 ret = -EINVAL;
7133 mutex_unlock(&app_access_lock);
7134 break;
7135 }
7136 }
7137 /*
7138 * On targets where crypto clock is handled by HLOS,
7139 * if clk_access_cnt is zero and perf_enabled is false,
7140 * then the crypto clock was not enabled before sending cmd to
7141 * tz, qseecom will enable the clock to avoid service failure.
7142 */
7143 if (!qseecom.no_clock_support &&
7144 !qseecom.qsee.clk_access_cnt && !data->perf_enabled) {
7145 pr_debug("ce clock is not enabled!\n");
7146 ret = qseecom_perf_enable(data);
7147 if (ret) {
7148 pr_err("Failed to vote for clock with err %d\n",
7149 ret);
7150 mutex_unlock(&app_access_lock);
7151 ret = -EINVAL;
7152 break;
7153 }
7154 perf_enabled = true;
7155 }
7156 atomic_inc(&data->ioctl_count);
7157 ret = qseecom_send_cmd(data, argp);
7158 if (qseecom.support_bus_scaling)
7159 __qseecom_add_bw_scale_down_timer(
7160 QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
7161 if (perf_enabled) {
7162 qsee_disable_clock_vote(data, CLK_DFAB);
7163 qsee_disable_clock_vote(data, CLK_SFPB);
7164 }
7165 atomic_dec(&data->ioctl_count);
7166 wake_up_all(&data->abort_wq);
7167 mutex_unlock(&app_access_lock);
7168 if (ret)
7169 pr_err("failed qseecom_send_cmd: %d\n", ret);
7170 break;
7171 }
7172 case QSEECOM_IOCTL_SEND_MODFD_CMD_REQ:
7173 case QSEECOM_IOCTL_SEND_MODFD_CMD_64_REQ: {
7174 if ((data->client.app_id == 0) ||
7175 (data->type != QSEECOM_CLIENT_APP)) {
7176 pr_err("send mdfd cmd: invalid handle (%d) appid(%d)\n",
7177 data->type, data->client.app_id);
7178 ret = -EINVAL;
7179 break;
7180 }
7181 /* Only one client allowed here at a time */
7182 mutex_lock(&app_access_lock);
7183 if (qseecom.support_bus_scaling) {
7184 if (!data->mode) {
7185 mutex_lock(&qsee_bw_mutex);
7186 __qseecom_register_bus_bandwidth_needs(
7187 data, HIGH);
7188 mutex_unlock(&qsee_bw_mutex);
7189 }
7190 ret = qseecom_scale_bus_bandwidth_timer(INACTIVE);
7191 if (ret) {
7192 pr_err("Failed to set bw.\n");
7193 mutex_unlock(&app_access_lock);
7194 ret = -EINVAL;
7195 break;
7196 }
7197 }
7198 /*
7199 * On targets where crypto clock is handled by HLOS,
7200 * if clk_access_cnt is zero and perf_enabled is false,
7201 * then the crypto clock was not enabled before sending cmd to
7202 * tz, qseecom will enable the clock to avoid service failure.
7203 */
7204 if (!qseecom.no_clock_support &&
7205 !qseecom.qsee.clk_access_cnt && !data->perf_enabled) {
7206 pr_debug("ce clock is not enabled!\n");
7207 ret = qseecom_perf_enable(data);
7208 if (ret) {
7209 pr_err("Failed to vote for clock with err %d\n",
7210 ret);
7211 mutex_unlock(&app_access_lock);
7212 ret = -EINVAL;
7213 break;
7214 }
7215 perf_enabled = true;
7216 }
7217 atomic_inc(&data->ioctl_count);
7218 if (cmd == QSEECOM_IOCTL_SEND_MODFD_CMD_REQ)
7219 ret = qseecom_send_modfd_cmd(data, argp);
7220 else
7221 ret = qseecom_send_modfd_cmd_64(data, argp);
7222 if (qseecom.support_bus_scaling)
7223 __qseecom_add_bw_scale_down_timer(
7224 QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
7225 if (perf_enabled) {
7226 qsee_disable_clock_vote(data, CLK_DFAB);
7227 qsee_disable_clock_vote(data, CLK_SFPB);
7228 }
7229 atomic_dec(&data->ioctl_count);
7230 wake_up_all(&data->abort_wq);
7231 mutex_unlock(&app_access_lock);
7232 if (ret)
7233 pr_err("failed qseecom_send_cmd: %d\n", ret);
7234 __qseecom_clean_data_sglistinfo(data);
7235 break;
7236 }
7237 case QSEECOM_IOCTL_RECEIVE_REQ: {
7238 if ((data->listener.id == 0) ||
7239 (data->type != QSEECOM_LISTENER_SERVICE)) {
7240 pr_err("receive req: invalid handle (%d), lid(%d)\n",
7241 data->type, data->listener.id);
7242 ret = -EINVAL;
7243 break;
7244 }
7245 atomic_inc(&data->ioctl_count);
7246 ret = qseecom_receive_req(data);
7247 atomic_dec(&data->ioctl_count);
7248 wake_up_all(&data->abort_wq);
7249 if (ret && (ret != -ERESTARTSYS))
7250 pr_err("failed qseecom_receive_req: %d\n", ret);
7251 break;
7252 }
7253 case QSEECOM_IOCTL_SEND_RESP_REQ: {
7254 if ((data->listener.id == 0) ||
7255 (data->type != QSEECOM_LISTENER_SERVICE)) {
7256 pr_err("send resp req: invalid handle (%d), lid(%d)\n",
7257 data->type, data->listener.id);
7258 ret = -EINVAL;
7259 break;
7260 }
Zhen Kongbcdeda22018-11-16 13:50:51 -08007261 mutex_lock(&listener_access_lock);
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07007262 atomic_inc(&data->ioctl_count);
7263 if (!qseecom.qsee_reentrancy_support)
7264 ret = qseecom_send_resp();
7265 else
7266 ret = qseecom_reentrancy_send_resp(data);
7267 atomic_dec(&data->ioctl_count);
7268 wake_up_all(&data->abort_wq);
Zhen Kongbcdeda22018-11-16 13:50:51 -08007269 mutex_unlock(&listener_access_lock);
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07007270 if (ret)
7271 pr_err("failed qseecom_send_resp: %d\n", ret);
7272 break;
7273 }
7274 case QSEECOM_IOCTL_SET_MEM_PARAM_REQ: {
7275 if ((data->type != QSEECOM_CLIENT_APP) &&
7276 (data->type != QSEECOM_GENERIC) &&
7277 (data->type != QSEECOM_SECURE_SERVICE)) {
7278 pr_err("set mem param req: invalid handle (%d)\n",
7279 data->type);
7280 ret = -EINVAL;
7281 break;
7282 }
7283 pr_debug("SET_MEM_PARAM: qseecom addr = 0x%pK\n", data);
7284 mutex_lock(&app_access_lock);
7285 atomic_inc(&data->ioctl_count);
7286 ret = qseecom_set_client_mem_param(data, argp);
7287 atomic_dec(&data->ioctl_count);
7288 mutex_unlock(&app_access_lock);
7289 if (ret)
7290 pr_err("failed Qqseecom_set_mem_param request: %d\n",
7291 ret);
7292 break;
7293 }
7294 case QSEECOM_IOCTL_LOAD_APP_REQ: {
7295 if ((data->type != QSEECOM_GENERIC) &&
7296 (data->type != QSEECOM_CLIENT_APP)) {
7297 pr_err("load app req: invalid handle (%d)\n",
7298 data->type);
7299 ret = -EINVAL;
7300 break;
7301 }
7302 data->type = QSEECOM_CLIENT_APP;
7303 pr_debug("LOAD_APP_REQ: qseecom_addr = 0x%pK\n", data);
7304 mutex_lock(&app_access_lock);
7305 atomic_inc(&data->ioctl_count);
7306 ret = qseecom_load_app(data, argp);
7307 atomic_dec(&data->ioctl_count);
7308 mutex_unlock(&app_access_lock);
7309 if (ret)
7310 pr_err("failed load_app request: %d\n", ret);
7311 break;
7312 }
7313 case QSEECOM_IOCTL_UNLOAD_APP_REQ: {
7314 if ((data->client.app_id == 0) ||
7315 (data->type != QSEECOM_CLIENT_APP)) {
7316 pr_err("unload app req:invalid handle(%d) app_id(%d)\n",
7317 data->type, data->client.app_id);
7318 ret = -EINVAL;
7319 break;
7320 }
7321 pr_debug("UNLOAD_APP: qseecom_addr = 0x%pK\n", data);
7322 mutex_lock(&app_access_lock);
7323 atomic_inc(&data->ioctl_count);
7324 ret = qseecom_unload_app(data, false);
7325 atomic_dec(&data->ioctl_count);
7326 mutex_unlock(&app_access_lock);
7327 if (ret)
7328 pr_err("failed unload_app request: %d\n", ret);
7329 break;
7330 }
7331 case QSEECOM_IOCTL_GET_QSEOS_VERSION_REQ: {
7332 atomic_inc(&data->ioctl_count);
7333 ret = qseecom_get_qseos_version(data, argp);
7334 if (ret)
7335 pr_err("qseecom_get_qseos_version: %d\n", ret);
7336 atomic_dec(&data->ioctl_count);
7337 break;
7338 }
7339 case QSEECOM_IOCTL_PERF_ENABLE_REQ:{
7340 if ((data->type != QSEECOM_GENERIC) &&
7341 (data->type != QSEECOM_CLIENT_APP)) {
7342 pr_err("perf enable req: invalid handle (%d)\n",
7343 data->type);
7344 ret = -EINVAL;
7345 break;
7346 }
7347 if ((data->type == QSEECOM_CLIENT_APP) &&
7348 (data->client.app_id == 0)) {
7349 pr_err("perf enable req:invalid handle(%d) appid(%d)\n",
7350 data->type, data->client.app_id);
7351 ret = -EINVAL;
7352 break;
7353 }
7354 atomic_inc(&data->ioctl_count);
7355 if (qseecom.support_bus_scaling) {
7356 mutex_lock(&qsee_bw_mutex);
7357 __qseecom_register_bus_bandwidth_needs(data, HIGH);
7358 mutex_unlock(&qsee_bw_mutex);
7359 } else {
7360 ret = qseecom_perf_enable(data);
7361 if (ret)
7362 pr_err("Fail to vote for clocks %d\n", ret);
7363 }
7364 atomic_dec(&data->ioctl_count);
7365 break;
7366 }
7367 case QSEECOM_IOCTL_PERF_DISABLE_REQ:{
7368 if ((data->type != QSEECOM_SECURE_SERVICE) &&
7369 (data->type != QSEECOM_CLIENT_APP)) {
7370 pr_err("perf disable req: invalid handle (%d)\n",
7371 data->type);
7372 ret = -EINVAL;
7373 break;
7374 }
7375 if ((data->type == QSEECOM_CLIENT_APP) &&
7376 (data->client.app_id == 0)) {
7377 pr_err("perf disable: invalid handle (%d)app_id(%d)\n",
7378 data->type, data->client.app_id);
7379 ret = -EINVAL;
7380 break;
7381 }
7382 atomic_inc(&data->ioctl_count);
7383 if (!qseecom.support_bus_scaling) {
7384 qsee_disable_clock_vote(data, CLK_DFAB);
7385 qsee_disable_clock_vote(data, CLK_SFPB);
7386 } else {
7387 mutex_lock(&qsee_bw_mutex);
7388 qseecom_unregister_bus_bandwidth_needs(data);
7389 mutex_unlock(&qsee_bw_mutex);
7390 }
7391 atomic_dec(&data->ioctl_count);
7392 break;
7393 }
7394
7395 case QSEECOM_IOCTL_SET_BUS_SCALING_REQ: {
7396 /* If crypto clock is not handled by HLOS, return directly. */
7397 if (qseecom.no_clock_support) {
7398 pr_debug("crypto clock is not handled by HLOS\n");
7399 break;
7400 }
7401 if ((data->client.app_id == 0) ||
7402 (data->type != QSEECOM_CLIENT_APP)) {
7403 pr_err("set bus scale: invalid handle (%d) appid(%d)\n",
7404 data->type, data->client.app_id);
7405 ret = -EINVAL;
7406 break;
7407 }
7408 atomic_inc(&data->ioctl_count);
7409 ret = qseecom_scale_bus_bandwidth(data, argp);
7410 atomic_dec(&data->ioctl_count);
7411 break;
7412 }
7413 case QSEECOM_IOCTL_LOAD_EXTERNAL_ELF_REQ: {
7414 if (data->type != QSEECOM_GENERIC) {
7415 pr_err("load ext elf req: invalid client handle (%d)\n",
7416 data->type);
7417 ret = -EINVAL;
7418 break;
7419 }
7420 data->type = QSEECOM_UNAVAILABLE_CLIENT_APP;
7421 data->released = true;
7422 mutex_lock(&app_access_lock);
7423 atomic_inc(&data->ioctl_count);
7424 ret = qseecom_load_external_elf(data, argp);
7425 atomic_dec(&data->ioctl_count);
7426 mutex_unlock(&app_access_lock);
7427 if (ret)
7428 pr_err("failed load_external_elf request: %d\n", ret);
7429 break;
7430 }
7431 case QSEECOM_IOCTL_UNLOAD_EXTERNAL_ELF_REQ: {
7432 if (data->type != QSEECOM_UNAVAILABLE_CLIENT_APP) {
7433 pr_err("unload ext elf req: invalid handle (%d)\n",
7434 data->type);
7435 ret = -EINVAL;
7436 break;
7437 }
7438 data->released = true;
7439 mutex_lock(&app_access_lock);
7440 atomic_inc(&data->ioctl_count);
7441 ret = qseecom_unload_external_elf(data);
7442 atomic_dec(&data->ioctl_count);
7443 mutex_unlock(&app_access_lock);
7444 if (ret)
7445 pr_err("failed unload_app request: %d\n", ret);
7446 break;
7447 }
7448 case QSEECOM_IOCTL_APP_LOADED_QUERY_REQ: {
7449 data->type = QSEECOM_CLIENT_APP;
7450 mutex_lock(&app_access_lock);
7451 atomic_inc(&data->ioctl_count);
7452 pr_debug("APP_LOAD_QUERY: qseecom_addr = 0x%pK\n", data);
7453 ret = qseecom_query_app_loaded(data, argp);
7454 atomic_dec(&data->ioctl_count);
7455 mutex_unlock(&app_access_lock);
7456 break;
7457 }
7458 case QSEECOM_IOCTL_SEND_CMD_SERVICE_REQ: {
7459 if (data->type != QSEECOM_GENERIC) {
7460 pr_err("send cmd svc req: invalid handle (%d)\n",
7461 data->type);
7462 ret = -EINVAL;
7463 break;
7464 }
7465 data->type = QSEECOM_SECURE_SERVICE;
7466 if (qseecom.qsee_version < QSEE_VERSION_03) {
7467 pr_err("SEND_CMD_SERVICE_REQ: Invalid qsee ver %u\n",
7468 qseecom.qsee_version);
7469 return -EINVAL;
7470 }
7471 mutex_lock(&app_access_lock);
7472 atomic_inc(&data->ioctl_count);
7473 ret = qseecom_send_service_cmd(data, argp);
7474 atomic_dec(&data->ioctl_count);
7475 mutex_unlock(&app_access_lock);
7476 break;
7477 }
7478 case QSEECOM_IOCTL_CREATE_KEY_REQ: {
7479 if (!(qseecom.support_pfe || qseecom.support_fde))
7480 pr_err("Features requiring key init not supported\n");
7481 if (data->type != QSEECOM_GENERIC) {
7482 pr_err("create key req: invalid handle (%d)\n",
7483 data->type);
7484 ret = -EINVAL;
7485 break;
7486 }
7487 if (qseecom.qsee_version < QSEE_VERSION_05) {
7488 pr_err("Create Key feature unsupported: qsee ver %u\n",
7489 qseecom.qsee_version);
7490 return -EINVAL;
7491 }
7492 data->released = true;
7493 mutex_lock(&app_access_lock);
7494 atomic_inc(&data->ioctl_count);
7495 ret = qseecom_create_key(data, argp);
7496 if (ret)
7497 pr_err("failed to create encryption key: %d\n", ret);
7498
7499 atomic_dec(&data->ioctl_count);
7500 mutex_unlock(&app_access_lock);
7501 break;
7502 }
7503 case QSEECOM_IOCTL_WIPE_KEY_REQ: {
7504 if (!(qseecom.support_pfe || qseecom.support_fde))
7505 pr_err("Features requiring key init not supported\n");
7506 if (data->type != QSEECOM_GENERIC) {
7507 pr_err("wipe key req: invalid handle (%d)\n",
7508 data->type);
7509 ret = -EINVAL;
7510 break;
7511 }
7512 if (qseecom.qsee_version < QSEE_VERSION_05) {
7513 pr_err("Wipe Key feature unsupported in qsee ver %u\n",
7514 qseecom.qsee_version);
7515 return -EINVAL;
7516 }
7517 data->released = true;
7518 mutex_lock(&app_access_lock);
7519 atomic_inc(&data->ioctl_count);
7520 ret = qseecom_wipe_key(data, argp);
7521 if (ret)
7522 pr_err("failed to wipe encryption key: %d\n", ret);
7523 atomic_dec(&data->ioctl_count);
7524 mutex_unlock(&app_access_lock);
7525 break;
7526 }
7527 case QSEECOM_IOCTL_UPDATE_KEY_USER_INFO_REQ: {
7528 if (!(qseecom.support_pfe || qseecom.support_fde))
7529 pr_err("Features requiring key init not supported\n");
7530 if (data->type != QSEECOM_GENERIC) {
7531 pr_err("update key req: invalid handle (%d)\n",
7532 data->type);
7533 ret = -EINVAL;
7534 break;
7535 }
7536 if (qseecom.qsee_version < QSEE_VERSION_05) {
7537 pr_err("Update Key feature unsupported in qsee ver %u\n",
7538 qseecom.qsee_version);
7539 return -EINVAL;
7540 }
7541 data->released = true;
7542 mutex_lock(&app_access_lock);
7543 atomic_inc(&data->ioctl_count);
7544 ret = qseecom_update_key_user_info(data, argp);
7545 if (ret)
7546 pr_err("failed to update key user info: %d\n", ret);
7547 atomic_dec(&data->ioctl_count);
7548 mutex_unlock(&app_access_lock);
7549 break;
7550 }
7551 case QSEECOM_IOCTL_SAVE_PARTITION_HASH_REQ: {
7552 if (data->type != QSEECOM_GENERIC) {
7553 pr_err("save part hash req: invalid handle (%d)\n",
7554 data->type);
7555 ret = -EINVAL;
7556 break;
7557 }
7558 data->released = true;
7559 mutex_lock(&app_access_lock);
7560 atomic_inc(&data->ioctl_count);
7561 ret = qseecom_save_partition_hash(argp);
7562 atomic_dec(&data->ioctl_count);
7563 mutex_unlock(&app_access_lock);
7564 break;
7565 }
7566 case QSEECOM_IOCTL_IS_ES_ACTIVATED_REQ: {
7567 if (data->type != QSEECOM_GENERIC) {
7568 pr_err("ES activated req: invalid handle (%d)\n",
7569 data->type);
7570 ret = -EINVAL;
7571 break;
7572 }
7573 data->released = true;
7574 mutex_lock(&app_access_lock);
7575 atomic_inc(&data->ioctl_count);
7576 ret = qseecom_is_es_activated(argp);
7577 atomic_dec(&data->ioctl_count);
7578 mutex_unlock(&app_access_lock);
7579 break;
7580 }
7581 case QSEECOM_IOCTL_MDTP_CIPHER_DIP_REQ: {
7582 if (data->type != QSEECOM_GENERIC) {
7583 pr_err("MDTP cipher DIP req: invalid handle (%d)\n",
7584 data->type);
7585 ret = -EINVAL;
7586 break;
7587 }
7588 data->released = true;
7589 mutex_lock(&app_access_lock);
7590 atomic_inc(&data->ioctl_count);
7591 ret = qseecom_mdtp_cipher_dip(argp);
7592 atomic_dec(&data->ioctl_count);
7593 mutex_unlock(&app_access_lock);
7594 break;
7595 }
7596 case QSEECOM_IOCTL_SEND_MODFD_RESP:
7597 case QSEECOM_IOCTL_SEND_MODFD_RESP_64: {
7598 if ((data->listener.id == 0) ||
7599 (data->type != QSEECOM_LISTENER_SERVICE)) {
7600 pr_err("receive req: invalid handle (%d), lid(%d)\n",
7601 data->type, data->listener.id);
7602 ret = -EINVAL;
7603 break;
7604 }
Zhen Kongbcdeda22018-11-16 13:50:51 -08007605 mutex_lock(&listener_access_lock);
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07007606 atomic_inc(&data->ioctl_count);
7607 if (cmd == QSEECOM_IOCTL_SEND_MODFD_RESP)
7608 ret = qseecom_send_modfd_resp(data, argp);
7609 else
7610 ret = qseecom_send_modfd_resp_64(data, argp);
7611 atomic_dec(&data->ioctl_count);
7612 wake_up_all(&data->abort_wq);
Zhen Kongbcdeda22018-11-16 13:50:51 -08007613 mutex_unlock(&listener_access_lock);
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07007614 if (ret)
7615 pr_err("failed qseecom_send_mod_resp: %d\n", ret);
7616 __qseecom_clean_data_sglistinfo(data);
7617 break;
7618 }
7619 case QSEECOM_QTEEC_IOCTL_OPEN_SESSION_REQ: {
7620 if ((data->client.app_id == 0) ||
7621 (data->type != QSEECOM_CLIENT_APP)) {
7622 pr_err("Open session: invalid handle (%d) appid(%d)\n",
7623 data->type, data->client.app_id);
7624 ret = -EINVAL;
7625 break;
7626 }
7627 if (qseecom.qsee_version < QSEE_VERSION_40) {
7628 pr_err("GP feature unsupported: qsee ver %u\n",
7629 qseecom.qsee_version);
7630 return -EINVAL;
7631 }
7632 /* Only one client allowed here at a time */
7633 mutex_lock(&app_access_lock);
7634 atomic_inc(&data->ioctl_count);
7635 ret = qseecom_qteec_open_session(data, argp);
7636 atomic_dec(&data->ioctl_count);
7637 wake_up_all(&data->abort_wq);
7638 mutex_unlock(&app_access_lock);
7639 if (ret)
7640 pr_err("failed open_session_cmd: %d\n", ret);
7641 __qseecom_clean_data_sglistinfo(data);
7642 break;
7643 }
7644 case QSEECOM_QTEEC_IOCTL_CLOSE_SESSION_REQ: {
7645 if ((data->client.app_id == 0) ||
7646 (data->type != QSEECOM_CLIENT_APP)) {
7647 pr_err("Close session: invalid handle (%d) appid(%d)\n",
7648 data->type, data->client.app_id);
7649 ret = -EINVAL;
7650 break;
7651 }
7652 if (qseecom.qsee_version < QSEE_VERSION_40) {
7653 pr_err("GP feature unsupported: qsee ver %u\n",
7654 qseecom.qsee_version);
7655 return -EINVAL;
7656 }
7657 /* Only one client allowed here at a time */
7658 mutex_lock(&app_access_lock);
7659 atomic_inc(&data->ioctl_count);
7660 ret = qseecom_qteec_close_session(data, argp);
7661 atomic_dec(&data->ioctl_count);
7662 wake_up_all(&data->abort_wq);
7663 mutex_unlock(&app_access_lock);
7664 if (ret)
7665 pr_err("failed close_session_cmd: %d\n", ret);
7666 break;
7667 }
7668 case QSEECOM_QTEEC_IOCTL_INVOKE_MODFD_CMD_REQ: {
7669 if ((data->client.app_id == 0) ||
7670 (data->type != QSEECOM_CLIENT_APP)) {
7671 pr_err("Invoke cmd: invalid handle (%d) appid(%d)\n",
7672 data->type, data->client.app_id);
7673 ret = -EINVAL;
7674 break;
7675 }
7676 if (qseecom.qsee_version < QSEE_VERSION_40) {
7677 pr_err("GP feature unsupported: qsee ver %u\n",
7678 qseecom.qsee_version);
7679 return -EINVAL;
7680 }
7681 /* Only one client allowed here at a time */
7682 mutex_lock(&app_access_lock);
7683 atomic_inc(&data->ioctl_count);
7684 ret = qseecom_qteec_invoke_modfd_cmd(data, argp);
7685 atomic_dec(&data->ioctl_count);
7686 wake_up_all(&data->abort_wq);
7687 mutex_unlock(&app_access_lock);
7688 if (ret)
7689 pr_err("failed Invoke cmd: %d\n", ret);
7690 __qseecom_clean_data_sglistinfo(data);
7691 break;
7692 }
7693 case QSEECOM_QTEEC_IOCTL_REQUEST_CANCELLATION_REQ: {
7694 if ((data->client.app_id == 0) ||
7695 (data->type != QSEECOM_CLIENT_APP)) {
7696 pr_err("Cancel req: invalid handle (%d) appid(%d)\n",
7697 data->type, data->client.app_id);
7698 ret = -EINVAL;
7699 break;
7700 }
7701 if (qseecom.qsee_version < QSEE_VERSION_40) {
7702 pr_err("GP feature unsupported: qsee ver %u\n",
7703 qseecom.qsee_version);
7704 return -EINVAL;
7705 }
7706 /* Only one client allowed here at a time */
7707 mutex_lock(&app_access_lock);
7708 atomic_inc(&data->ioctl_count);
7709 ret = qseecom_qteec_request_cancellation(data, argp);
7710 atomic_dec(&data->ioctl_count);
7711 wake_up_all(&data->abort_wq);
7712 mutex_unlock(&app_access_lock);
7713 if (ret)
7714 pr_err("failed request_cancellation: %d\n", ret);
7715 break;
7716 }
7717 case QSEECOM_IOCTL_GET_CE_PIPE_INFO: {
7718 atomic_inc(&data->ioctl_count);
7719 ret = qseecom_get_ce_info(data, argp);
7720 if (ret)
7721 pr_err("failed get fde ce pipe info: %d\n", ret);
7722 atomic_dec(&data->ioctl_count);
7723 break;
7724 }
7725 case QSEECOM_IOCTL_FREE_CE_PIPE_INFO: {
7726 atomic_inc(&data->ioctl_count);
7727 ret = qseecom_free_ce_info(data, argp);
7728 if (ret)
7729 pr_err("failed get fde ce pipe info: %d\n", ret);
7730 atomic_dec(&data->ioctl_count);
7731 break;
7732 }
7733 case QSEECOM_IOCTL_QUERY_CE_PIPE_INFO: {
7734 atomic_inc(&data->ioctl_count);
7735 ret = qseecom_query_ce_info(data, argp);
7736 if (ret)
7737 pr_err("failed get fde ce pipe info: %d\n", ret);
7738 atomic_dec(&data->ioctl_count);
7739 break;
7740 }
7741 default:
7742 pr_err("Invalid IOCTL: 0x%x\n", cmd);
7743 return -EINVAL;
7744 }
7745 return ret;
7746}
7747
7748static int qseecom_open(struct inode *inode, struct file *file)
7749{
7750 int ret = 0;
7751 struct qseecom_dev_handle *data;
7752
7753 data = kzalloc(sizeof(*data), GFP_KERNEL);
7754 if (!data)
7755 return -ENOMEM;
7756 file->private_data = data;
7757 data->abort = 0;
7758 data->type = QSEECOM_GENERIC;
7759 data->released = false;
7760 memset((void *)data->client.app_name, 0, MAX_APP_NAME_SIZE);
7761 data->mode = INACTIVE;
7762 init_waitqueue_head(&data->abort_wq);
7763 atomic_set(&data->ioctl_count, 0);
7764 return ret;
7765}
7766
7767static int qseecom_release(struct inode *inode, struct file *file)
7768{
7769 struct qseecom_dev_handle *data = file->private_data;
7770 int ret = 0;
Zhen Kongbcdeda22018-11-16 13:50:51 -08007771 bool free_private_data = true;
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07007772
7773 if (data->released == false) {
7774 pr_debug("data: released=false, type=%d, mode=%d, data=0x%pK\n",
7775 data->type, data->mode, data);
7776 switch (data->type) {
7777 case QSEECOM_LISTENER_SERVICE:
Zhen Kongbcdeda22018-11-16 13:50:51 -08007778 pr_debug("release lsnr svc %d\n", data->listener.id);
7779 free_private_data = false;
7780 mutex_lock(&listener_access_lock);
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07007781 ret = qseecom_unregister_listener(data);
Zhen Kong87dcf0e2019-01-04 12:34:50 -08007782 data->listener.release_called = true;
Zhen Kongbcdeda22018-11-16 13:50:51 -08007783 mutex_unlock(&listener_access_lock);
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07007784 break;
7785 case QSEECOM_CLIENT_APP:
7786 mutex_lock(&app_access_lock);
7787 ret = qseecom_unload_app(data, true);
7788 mutex_unlock(&app_access_lock);
7789 break;
7790 case QSEECOM_SECURE_SERVICE:
7791 case QSEECOM_GENERIC:
7792 ret = qseecom_unmap_ion_allocated_memory(data);
7793 if (ret)
7794 pr_err("Ion Unmap failed\n");
7795 break;
7796 case QSEECOM_UNAVAILABLE_CLIENT_APP:
7797 break;
7798 default:
7799 pr_err("Unsupported clnt_handle_type %d",
7800 data->type);
7801 break;
7802 }
7803 }
7804
7805 if (qseecom.support_bus_scaling) {
7806 mutex_lock(&qsee_bw_mutex);
7807 if (data->mode != INACTIVE) {
7808 qseecom_unregister_bus_bandwidth_needs(data);
7809 if (qseecom.cumulative_mode == INACTIVE) {
7810 ret = __qseecom_set_msm_bus_request(INACTIVE);
7811 if (ret)
7812 pr_err("Fail to scale down bus\n");
7813 }
7814 }
7815 mutex_unlock(&qsee_bw_mutex);
7816 } else {
7817 if (data->fast_load_enabled == true)
7818 qsee_disable_clock_vote(data, CLK_SFPB);
7819 if (data->perf_enabled == true)
7820 qsee_disable_clock_vote(data, CLK_DFAB);
7821 }
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07007822
Zhen Kongbcdeda22018-11-16 13:50:51 -08007823 if (free_private_data)
7824 kfree(data);
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07007825 return ret;
7826}
7827
7828#ifdef CONFIG_COMPAT
7829#include "compat_qseecom.c"
7830#else
7831#define compat_qseecom_ioctl NULL
7832#endif
7833
7834static const struct file_operations qseecom_fops = {
7835 .owner = THIS_MODULE,
7836 .unlocked_ioctl = qseecom_ioctl,
7837 .compat_ioctl = compat_qseecom_ioctl,
7838 .open = qseecom_open,
7839 .release = qseecom_release
7840};
7841
7842static int __qseecom_init_clk(enum qseecom_ce_hw_instance ce)
7843{
7844 int rc = 0;
7845 struct device *pdev;
7846 struct qseecom_clk *qclk;
7847 char *core_clk_src = NULL;
7848 char *core_clk = NULL;
7849 char *iface_clk = NULL;
7850 char *bus_clk = NULL;
7851
7852 switch (ce) {
7853 case CLK_QSEE: {
7854 core_clk_src = "core_clk_src";
7855 core_clk = "core_clk";
7856 iface_clk = "iface_clk";
7857 bus_clk = "bus_clk";
7858 qclk = &qseecom.qsee;
7859 qclk->instance = CLK_QSEE;
7860 break;
7861 };
7862 case CLK_CE_DRV: {
7863 core_clk_src = "ce_drv_core_clk_src";
7864 core_clk = "ce_drv_core_clk";
7865 iface_clk = "ce_drv_iface_clk";
7866 bus_clk = "ce_drv_bus_clk";
7867 qclk = &qseecom.ce_drv;
7868 qclk->instance = CLK_CE_DRV;
7869 break;
7870 };
7871 default:
7872 pr_err("Invalid ce hw instance: %d!\n", ce);
7873 return -EIO;
7874 }
7875
7876 if (qseecom.no_clock_support) {
7877 qclk->ce_core_clk = NULL;
7878 qclk->ce_clk = NULL;
7879 qclk->ce_bus_clk = NULL;
7880 qclk->ce_core_src_clk = NULL;
7881 return 0;
7882 }
7883
7884 pdev = qseecom.pdev;
7885
7886 /* Get CE3 src core clk. */
7887 qclk->ce_core_src_clk = clk_get(pdev, core_clk_src);
7888 if (!IS_ERR(qclk->ce_core_src_clk)) {
7889 rc = clk_set_rate(qclk->ce_core_src_clk,
7890 qseecom.ce_opp_freq_hz);
7891 if (rc) {
7892 clk_put(qclk->ce_core_src_clk);
7893 qclk->ce_core_src_clk = NULL;
7894 pr_err("Unable to set the core src clk @%uMhz.\n",
7895 qseecom.ce_opp_freq_hz/CE_CLK_DIV);
7896 return -EIO;
7897 }
7898 } else {
7899 pr_warn("Unable to get CE core src clk, set to NULL\n");
7900 qclk->ce_core_src_clk = NULL;
7901 }
7902
7903 /* Get CE core clk */
7904 qclk->ce_core_clk = clk_get(pdev, core_clk);
7905 if (IS_ERR(qclk->ce_core_clk)) {
7906 rc = PTR_ERR(qclk->ce_core_clk);
7907 pr_err("Unable to get CE core clk\n");
7908 if (qclk->ce_core_src_clk != NULL)
7909 clk_put(qclk->ce_core_src_clk);
7910 return -EIO;
7911 }
7912
7913 /* Get CE Interface clk */
7914 qclk->ce_clk = clk_get(pdev, iface_clk);
7915 if (IS_ERR(qclk->ce_clk)) {
7916 rc = PTR_ERR(qclk->ce_clk);
7917 pr_err("Unable to get CE interface clk\n");
7918 if (qclk->ce_core_src_clk != NULL)
7919 clk_put(qclk->ce_core_src_clk);
7920 clk_put(qclk->ce_core_clk);
7921 return -EIO;
7922 }
7923
7924 /* Get CE AXI clk */
7925 qclk->ce_bus_clk = clk_get(pdev, bus_clk);
7926 if (IS_ERR(qclk->ce_bus_clk)) {
7927 rc = PTR_ERR(qclk->ce_bus_clk);
7928 pr_err("Unable to get CE BUS interface clk\n");
7929 if (qclk->ce_core_src_clk != NULL)
7930 clk_put(qclk->ce_core_src_clk);
7931 clk_put(qclk->ce_core_clk);
7932 clk_put(qclk->ce_clk);
7933 return -EIO;
7934 }
7935
7936 return rc;
7937}
7938
7939static void __qseecom_deinit_clk(enum qseecom_ce_hw_instance ce)
7940{
7941 struct qseecom_clk *qclk;
7942
7943 if (ce == CLK_QSEE)
7944 qclk = &qseecom.qsee;
7945 else
7946 qclk = &qseecom.ce_drv;
7947
7948 if (qclk->ce_clk != NULL) {
7949 clk_put(qclk->ce_clk);
7950 qclk->ce_clk = NULL;
7951 }
7952 if (qclk->ce_core_clk != NULL) {
7953 clk_put(qclk->ce_core_clk);
7954 qclk->ce_core_clk = NULL;
7955 }
7956 if (qclk->ce_bus_clk != NULL) {
7957 clk_put(qclk->ce_bus_clk);
7958 qclk->ce_bus_clk = NULL;
7959 }
7960 if (qclk->ce_core_src_clk != NULL) {
7961 clk_put(qclk->ce_core_src_clk);
7962 qclk->ce_core_src_clk = NULL;
7963 }
7964 qclk->instance = CLK_INVALID;
7965}
7966
7967static int qseecom_retrieve_ce_data(struct platform_device *pdev)
7968{
7969 int rc = 0;
7970 uint32_t hlos_num_ce_hw_instances;
7971 uint32_t disk_encrypt_pipe;
7972 uint32_t file_encrypt_pipe;
Zhen Kongffec45c2017-10-18 14:05:53 -07007973 uint32_t hlos_ce_hw_instance[MAX_CE_PIPE_PAIR_PER_UNIT] = {0};
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07007974 int i;
7975 const int *tbl;
7976 int size;
7977 int entry;
7978 struct qseecom_crypto_info *pfde_tbl = NULL;
7979 struct qseecom_crypto_info *p;
7980 int tbl_size;
7981 int j;
7982 bool old_db = true;
7983 struct qseecom_ce_info_use *pce_info_use;
7984 uint32_t *unit_tbl = NULL;
7985 int total_units = 0;
7986 struct qseecom_ce_pipe_entry *pce_entry;
7987
7988 qseecom.ce_info.fde = qseecom.ce_info.pfe = NULL;
7989 qseecom.ce_info.num_fde = qseecom.ce_info.num_pfe = 0;
7990
7991 if (of_property_read_u32((&pdev->dev)->of_node,
7992 "qcom,qsee-ce-hw-instance",
7993 &qseecom.ce_info.qsee_ce_hw_instance)) {
7994 pr_err("Fail to get qsee ce hw instance information.\n");
7995 rc = -EINVAL;
7996 goto out;
7997 } else {
7998 pr_debug("qsee-ce-hw-instance=0x%x\n",
7999 qseecom.ce_info.qsee_ce_hw_instance);
8000 }
8001
8002 qseecom.support_fde = of_property_read_bool((&pdev->dev)->of_node,
8003 "qcom,support-fde");
8004 qseecom.support_pfe = of_property_read_bool((&pdev->dev)->of_node,
8005 "qcom,support-pfe");
8006
8007 if (!qseecom.support_pfe && !qseecom.support_fde) {
8008 pr_warn("Device does not support PFE/FDE");
8009 goto out;
8010 }
8011
8012 if (qseecom.support_fde)
8013 tbl = of_get_property((&pdev->dev)->of_node,
8014 "qcom,full-disk-encrypt-info", &size);
8015 else
8016 tbl = NULL;
8017 if (tbl) {
8018 old_db = false;
8019 if (size % sizeof(struct qseecom_crypto_info)) {
8020 pr_err("full-disk-encrypt-info tbl size(%d)\n",
8021 size);
8022 rc = -EINVAL;
8023 goto out;
8024 }
8025 tbl_size = size / sizeof
8026 (struct qseecom_crypto_info);
8027
8028 pfde_tbl = kzalloc(size, GFP_KERNEL);
8029 unit_tbl = kcalloc(tbl_size, sizeof(int), GFP_KERNEL);
8030 total_units = 0;
8031
8032 if (!pfde_tbl || !unit_tbl) {
8033 pr_err("failed to alloc memory\n");
8034 rc = -ENOMEM;
8035 goto out;
8036 }
8037 if (of_property_read_u32_array((&pdev->dev)->of_node,
8038 "qcom,full-disk-encrypt-info",
8039 (u32 *)pfde_tbl, size/sizeof(u32))) {
8040 pr_err("failed to read full-disk-encrypt-info tbl\n");
8041 rc = -EINVAL;
8042 goto out;
8043 }
8044
8045 for (i = 0, p = pfde_tbl; i < tbl_size; i++, p++) {
8046 for (j = 0; j < total_units; j++) {
8047 if (p->unit_num == *(unit_tbl + j))
8048 break;
8049 }
8050 if (j == total_units) {
8051 *(unit_tbl + total_units) = p->unit_num;
8052 total_units++;
8053 }
8054 }
8055
8056 qseecom.ce_info.num_fde = total_units;
8057 pce_info_use = qseecom.ce_info.fde = kcalloc(
8058 total_units, sizeof(struct qseecom_ce_info_use),
8059 GFP_KERNEL);
8060 if (!pce_info_use) {
8061 pr_err("failed to alloc memory\n");
8062 rc = -ENOMEM;
8063 goto out;
8064 }
8065
8066 for (j = 0; j < total_units; j++, pce_info_use++) {
8067 pce_info_use->unit_num = *(unit_tbl + j);
8068 pce_info_use->alloc = false;
8069 pce_info_use->type = CE_PIPE_PAIR_USE_TYPE_FDE;
8070 pce_info_use->num_ce_pipe_entries = 0;
8071 pce_info_use->ce_pipe_entry = NULL;
8072 for (i = 0, p = pfde_tbl; i < tbl_size; i++, p++) {
8073 if (p->unit_num == pce_info_use->unit_num)
8074 pce_info_use->num_ce_pipe_entries++;
8075 }
8076
8077 entry = pce_info_use->num_ce_pipe_entries;
8078 pce_entry = pce_info_use->ce_pipe_entry =
8079 kcalloc(entry,
8080 sizeof(struct qseecom_ce_pipe_entry),
8081 GFP_KERNEL);
8082 if (pce_entry == NULL) {
8083 pr_err("failed to alloc memory\n");
8084 rc = -ENOMEM;
8085 goto out;
8086 }
8087
8088 for (i = 0, p = pfde_tbl; i < tbl_size; i++, p++) {
8089 if (p->unit_num == pce_info_use->unit_num) {
8090 pce_entry->ce_num = p->ce;
8091 pce_entry->ce_pipe_pair =
8092 p->pipe_pair;
8093 pce_entry->valid = true;
8094 pce_entry++;
8095 }
8096 }
8097 }
8098 kfree(unit_tbl);
8099 unit_tbl = NULL;
8100 kfree(pfde_tbl);
8101 pfde_tbl = NULL;
8102 }
8103
8104 if (qseecom.support_pfe)
8105 tbl = of_get_property((&pdev->dev)->of_node,
8106 "qcom,per-file-encrypt-info", &size);
8107 else
8108 tbl = NULL;
8109 if (tbl) {
8110 old_db = false;
8111 if (size % sizeof(struct qseecom_crypto_info)) {
8112 pr_err("per-file-encrypt-info tbl size(%d)\n",
8113 size);
8114 rc = -EINVAL;
8115 goto out;
8116 }
8117 tbl_size = size / sizeof
8118 (struct qseecom_crypto_info);
8119
8120 pfde_tbl = kzalloc(size, GFP_KERNEL);
8121 unit_tbl = kcalloc(tbl_size, sizeof(int), GFP_KERNEL);
8122 total_units = 0;
8123 if (!pfde_tbl || !unit_tbl) {
8124 pr_err("failed to alloc memory\n");
8125 rc = -ENOMEM;
8126 goto out;
8127 }
8128 if (of_property_read_u32_array((&pdev->dev)->of_node,
8129 "qcom,per-file-encrypt-info",
8130 (u32 *)pfde_tbl, size/sizeof(u32))) {
8131 pr_err("failed to read per-file-encrypt-info tbl\n");
8132 rc = -EINVAL;
8133 goto out;
8134 }
8135
8136 for (i = 0, p = pfde_tbl; i < tbl_size; i++, p++) {
8137 for (j = 0; j < total_units; j++) {
8138 if (p->unit_num == *(unit_tbl + j))
8139 break;
8140 }
8141 if (j == total_units) {
8142 *(unit_tbl + total_units) = p->unit_num;
8143 total_units++;
8144 }
8145 }
8146
8147 qseecom.ce_info.num_pfe = total_units;
8148 pce_info_use = qseecom.ce_info.pfe = kcalloc(
8149 total_units, sizeof(struct qseecom_ce_info_use),
8150 GFP_KERNEL);
8151 if (!pce_info_use) {
8152 pr_err("failed to alloc memory\n");
8153 rc = -ENOMEM;
8154 goto out;
8155 }
8156
8157 for (j = 0; j < total_units; j++, pce_info_use++) {
8158 pce_info_use->unit_num = *(unit_tbl + j);
8159 pce_info_use->alloc = false;
8160 pce_info_use->type = CE_PIPE_PAIR_USE_TYPE_PFE;
8161 pce_info_use->num_ce_pipe_entries = 0;
8162 pce_info_use->ce_pipe_entry = NULL;
8163 for (i = 0, p = pfde_tbl; i < tbl_size; i++, p++) {
8164 if (p->unit_num == pce_info_use->unit_num)
8165 pce_info_use->num_ce_pipe_entries++;
8166 }
8167
8168 entry = pce_info_use->num_ce_pipe_entries;
8169 pce_entry = pce_info_use->ce_pipe_entry =
8170 kcalloc(entry,
8171 sizeof(struct qseecom_ce_pipe_entry),
8172 GFP_KERNEL);
8173 if (pce_entry == NULL) {
8174 pr_err("failed to alloc memory\n");
8175 rc = -ENOMEM;
8176 goto out;
8177 }
8178
8179 for (i = 0, p = pfde_tbl; i < tbl_size; i++, p++) {
8180 if (p->unit_num == pce_info_use->unit_num) {
8181 pce_entry->ce_num = p->ce;
8182 pce_entry->ce_pipe_pair =
8183 p->pipe_pair;
8184 pce_entry->valid = true;
8185 pce_entry++;
8186 }
8187 }
8188 }
8189 kfree(unit_tbl);
8190 unit_tbl = NULL;
8191 kfree(pfde_tbl);
8192 pfde_tbl = NULL;
8193 }
8194
8195 if (!old_db)
8196 goto out1;
8197
8198 if (of_property_read_bool((&pdev->dev)->of_node,
8199 "qcom,support-multiple-ce-hw-instance")) {
8200 if (of_property_read_u32((&pdev->dev)->of_node,
8201 "qcom,hlos-num-ce-hw-instances",
8202 &hlos_num_ce_hw_instances)) {
8203 pr_err("Fail: get hlos number of ce hw instance\n");
8204 rc = -EINVAL;
8205 goto out;
8206 }
8207 } else {
8208 hlos_num_ce_hw_instances = 1;
8209 }
8210
8211 if (hlos_num_ce_hw_instances > MAX_CE_PIPE_PAIR_PER_UNIT) {
8212 pr_err("Fail: hlos number of ce hw instance exceeds %d\n",
8213 MAX_CE_PIPE_PAIR_PER_UNIT);
8214 rc = -EINVAL;
8215 goto out;
8216 }
8217
8218 if (of_property_read_u32_array((&pdev->dev)->of_node,
8219 "qcom,hlos-ce-hw-instance", hlos_ce_hw_instance,
8220 hlos_num_ce_hw_instances)) {
8221 pr_err("Fail: get hlos ce hw instance info\n");
8222 rc = -EINVAL;
8223 goto out;
8224 }
8225
8226 if (qseecom.support_fde) {
8227 pce_info_use = qseecom.ce_info.fde =
8228 kzalloc(sizeof(struct qseecom_ce_info_use), GFP_KERNEL);
8229 if (!pce_info_use) {
8230 pr_err("failed to alloc memory\n");
8231 rc = -ENOMEM;
8232 goto out;
8233 }
8234 /* by default for old db */
8235 qseecom.ce_info.num_fde = DEFAULT_NUM_CE_INFO_UNIT;
8236 pce_info_use->unit_num = DEFAULT_CE_INFO_UNIT;
8237 pce_info_use->alloc = false;
8238 pce_info_use->type = CE_PIPE_PAIR_USE_TYPE_FDE;
8239 pce_info_use->ce_pipe_entry = NULL;
8240 if (of_property_read_u32((&pdev->dev)->of_node,
8241 "qcom,disk-encrypt-pipe-pair",
8242 &disk_encrypt_pipe)) {
8243 pr_err("Fail to get FDE pipe information.\n");
8244 rc = -EINVAL;
8245 goto out;
8246 } else {
8247 pr_debug("disk-encrypt-pipe-pair=0x%x",
8248 disk_encrypt_pipe);
8249 }
8250 entry = pce_info_use->num_ce_pipe_entries =
8251 hlos_num_ce_hw_instances;
8252 pce_entry = pce_info_use->ce_pipe_entry =
8253 kcalloc(entry,
8254 sizeof(struct qseecom_ce_pipe_entry),
8255 GFP_KERNEL);
8256 if (pce_entry == NULL) {
8257 pr_err("failed to alloc memory\n");
8258 rc = -ENOMEM;
8259 goto out;
8260 }
8261 for (i = 0; i < entry; i++) {
8262 pce_entry->ce_num = hlos_ce_hw_instance[i];
8263 pce_entry->ce_pipe_pair = disk_encrypt_pipe;
8264 pce_entry->valid = 1;
8265 pce_entry++;
8266 }
8267 } else {
8268 pr_warn("Device does not support FDE");
8269 disk_encrypt_pipe = 0xff;
8270 }
8271 if (qseecom.support_pfe) {
8272 pce_info_use = qseecom.ce_info.pfe =
8273 kzalloc(sizeof(struct qseecom_ce_info_use), GFP_KERNEL);
8274 if (!pce_info_use) {
8275 pr_err("failed to alloc memory\n");
8276 rc = -ENOMEM;
8277 goto out;
8278 }
8279 /* by default for old db */
8280 qseecom.ce_info.num_pfe = DEFAULT_NUM_CE_INFO_UNIT;
8281 pce_info_use->unit_num = DEFAULT_CE_INFO_UNIT;
8282 pce_info_use->alloc = false;
8283 pce_info_use->type = CE_PIPE_PAIR_USE_TYPE_PFE;
8284 pce_info_use->ce_pipe_entry = NULL;
8285
8286 if (of_property_read_u32((&pdev->dev)->of_node,
8287 "qcom,file-encrypt-pipe-pair",
8288 &file_encrypt_pipe)) {
8289 pr_err("Fail to get PFE pipe information.\n");
8290 rc = -EINVAL;
8291 goto out;
8292 } else {
8293 pr_debug("file-encrypt-pipe-pair=0x%x",
8294 file_encrypt_pipe);
8295 }
8296 entry = pce_info_use->num_ce_pipe_entries =
8297 hlos_num_ce_hw_instances;
8298 pce_entry = pce_info_use->ce_pipe_entry =
8299 kcalloc(entry,
8300 sizeof(struct qseecom_ce_pipe_entry),
8301 GFP_KERNEL);
8302 if (pce_entry == NULL) {
8303 pr_err("failed to alloc memory\n");
8304 rc = -ENOMEM;
8305 goto out;
8306 }
8307 for (i = 0; i < entry; i++) {
8308 pce_entry->ce_num = hlos_ce_hw_instance[i];
8309 pce_entry->ce_pipe_pair = file_encrypt_pipe;
8310 pce_entry->valid = 1;
8311 pce_entry++;
8312 }
8313 } else {
8314 pr_warn("Device does not support PFE");
8315 file_encrypt_pipe = 0xff;
8316 }
8317
8318out1:
8319 qseecom.qsee.instance = qseecom.ce_info.qsee_ce_hw_instance;
8320 qseecom.ce_drv.instance = hlos_ce_hw_instance[0];
8321out:
8322 if (rc) {
8323 if (qseecom.ce_info.fde) {
8324 pce_info_use = qseecom.ce_info.fde;
8325 for (i = 0; i < qseecom.ce_info.num_fde; i++) {
8326 pce_entry = pce_info_use->ce_pipe_entry;
8327 kfree(pce_entry);
8328 pce_info_use++;
8329 }
8330 }
8331 kfree(qseecom.ce_info.fde);
8332 qseecom.ce_info.fde = NULL;
8333 if (qseecom.ce_info.pfe) {
8334 pce_info_use = qseecom.ce_info.pfe;
8335 for (i = 0; i < qseecom.ce_info.num_pfe; i++) {
8336 pce_entry = pce_info_use->ce_pipe_entry;
8337 kfree(pce_entry);
8338 pce_info_use++;
8339 }
8340 }
8341 kfree(qseecom.ce_info.pfe);
8342 qseecom.ce_info.pfe = NULL;
8343 }
8344 kfree(unit_tbl);
8345 kfree(pfde_tbl);
8346 return rc;
8347}
8348
8349static int qseecom_get_ce_info(struct qseecom_dev_handle *data,
8350 void __user *argp)
8351{
8352 struct qseecom_ce_info_req req;
8353 struct qseecom_ce_info_req *pinfo = &req;
8354 int ret = 0;
8355 int i;
8356 unsigned int entries;
8357 struct qseecom_ce_info_use *pce_info_use, *p;
8358 int total = 0;
8359 bool found = false;
8360 struct qseecom_ce_pipe_entry *pce_entry;
8361
8362 ret = copy_from_user(pinfo, argp,
8363 sizeof(struct qseecom_ce_info_req));
8364 if (ret) {
8365 pr_err("copy_from_user failed\n");
8366 return ret;
8367 }
8368
8369 switch (pinfo->usage) {
8370 case QSEOS_KM_USAGE_DISK_ENCRYPTION:
8371 case QSEOS_KM_USAGE_UFS_ICE_DISK_ENCRYPTION:
8372 case QSEOS_KM_USAGE_SDCC_ICE_DISK_ENCRYPTION:
8373 if (qseecom.support_fde) {
8374 p = qseecom.ce_info.fde;
8375 total = qseecom.ce_info.num_fde;
8376 } else {
8377 pr_err("system does not support fde\n");
8378 return -EINVAL;
8379 }
8380 break;
8381 case QSEOS_KM_USAGE_FILE_ENCRYPTION:
8382 if (qseecom.support_pfe) {
8383 p = qseecom.ce_info.pfe;
8384 total = qseecom.ce_info.num_pfe;
8385 } else {
8386 pr_err("system does not support pfe\n");
8387 return -EINVAL;
8388 }
8389 break;
8390 default:
8391 pr_err("unsupported usage %d\n", pinfo->usage);
8392 return -EINVAL;
8393 }
8394
8395 pce_info_use = NULL;
8396 for (i = 0; i < total; i++) {
8397 if (!p->alloc)
8398 pce_info_use = p;
8399 else if (!memcmp(p->handle, pinfo->handle,
8400 MAX_CE_INFO_HANDLE_SIZE)) {
8401 pce_info_use = p;
8402 found = true;
8403 break;
8404 }
8405 p++;
8406 }
8407
8408 if (pce_info_use == NULL)
8409 return -EBUSY;
8410
8411 pinfo->unit_num = pce_info_use->unit_num;
8412 if (!pce_info_use->alloc) {
8413 pce_info_use->alloc = true;
8414 memcpy(pce_info_use->handle,
8415 pinfo->handle, MAX_CE_INFO_HANDLE_SIZE);
8416 }
8417 if (pce_info_use->num_ce_pipe_entries >
8418 MAX_CE_PIPE_PAIR_PER_UNIT)
8419 entries = MAX_CE_PIPE_PAIR_PER_UNIT;
8420 else
8421 entries = pce_info_use->num_ce_pipe_entries;
8422 pinfo->num_ce_pipe_entries = entries;
8423 pce_entry = pce_info_use->ce_pipe_entry;
8424 for (i = 0; i < entries; i++, pce_entry++)
8425 pinfo->ce_pipe_entry[i] = *pce_entry;
8426 for (; i < MAX_CE_PIPE_PAIR_PER_UNIT; i++)
8427 pinfo->ce_pipe_entry[i].valid = 0;
8428
8429 if (copy_to_user(argp, pinfo, sizeof(struct qseecom_ce_info_req))) {
8430 pr_err("copy_to_user failed\n");
8431 ret = -EFAULT;
8432 }
8433 return ret;
8434}
8435
8436static int qseecom_free_ce_info(struct qseecom_dev_handle *data,
8437 void __user *argp)
8438{
8439 struct qseecom_ce_info_req req;
8440 struct qseecom_ce_info_req *pinfo = &req;
8441 int ret = 0;
8442 struct qseecom_ce_info_use *p;
8443 int total = 0;
8444 int i;
8445 bool found = false;
8446
8447 ret = copy_from_user(pinfo, argp,
8448 sizeof(struct qseecom_ce_info_req));
8449 if (ret)
8450 return ret;
8451
8452 switch (pinfo->usage) {
8453 case QSEOS_KM_USAGE_DISK_ENCRYPTION:
8454 case QSEOS_KM_USAGE_UFS_ICE_DISK_ENCRYPTION:
8455 case QSEOS_KM_USAGE_SDCC_ICE_DISK_ENCRYPTION:
8456 if (qseecom.support_fde) {
8457 p = qseecom.ce_info.fde;
8458 total = qseecom.ce_info.num_fde;
8459 } else {
8460 pr_err("system does not support fde\n");
8461 return -EINVAL;
8462 }
8463 break;
8464 case QSEOS_KM_USAGE_FILE_ENCRYPTION:
8465 if (qseecom.support_pfe) {
8466 p = qseecom.ce_info.pfe;
8467 total = qseecom.ce_info.num_pfe;
8468 } else {
8469 pr_err("system does not support pfe\n");
8470 return -EINVAL;
8471 }
8472 break;
8473 default:
8474 pr_err("unsupported usage %d\n", pinfo->usage);
8475 return -EINVAL;
8476 }
8477
8478 for (i = 0; i < total; i++) {
8479 if (p->alloc &&
8480 !memcmp(p->handle, pinfo->handle,
8481 MAX_CE_INFO_HANDLE_SIZE)) {
8482 memset(p->handle, 0, MAX_CE_INFO_HANDLE_SIZE);
8483 p->alloc = false;
8484 found = true;
8485 break;
8486 }
8487 p++;
8488 }
8489 return ret;
8490}
8491
8492static int qseecom_query_ce_info(struct qseecom_dev_handle *data,
8493 void __user *argp)
8494{
8495 struct qseecom_ce_info_req req;
8496 struct qseecom_ce_info_req *pinfo = &req;
8497 int ret = 0;
8498 int i;
8499 unsigned int entries;
8500 struct qseecom_ce_info_use *pce_info_use, *p;
8501 int total = 0;
8502 bool found = false;
8503 struct qseecom_ce_pipe_entry *pce_entry;
8504
8505 ret = copy_from_user(pinfo, argp,
8506 sizeof(struct qseecom_ce_info_req));
8507 if (ret)
8508 return ret;
8509
8510 switch (pinfo->usage) {
8511 case QSEOS_KM_USAGE_DISK_ENCRYPTION:
8512 case QSEOS_KM_USAGE_UFS_ICE_DISK_ENCRYPTION:
8513 case QSEOS_KM_USAGE_SDCC_ICE_DISK_ENCRYPTION:
8514 if (qseecom.support_fde) {
8515 p = qseecom.ce_info.fde;
8516 total = qseecom.ce_info.num_fde;
8517 } else {
8518 pr_err("system does not support fde\n");
8519 return -EINVAL;
8520 }
8521 break;
8522 case QSEOS_KM_USAGE_FILE_ENCRYPTION:
8523 if (qseecom.support_pfe) {
8524 p = qseecom.ce_info.pfe;
8525 total = qseecom.ce_info.num_pfe;
8526 } else {
8527 pr_err("system does not support pfe\n");
8528 return -EINVAL;
8529 }
8530 break;
8531 default:
8532 pr_err("unsupported usage %d\n", pinfo->usage);
8533 return -EINVAL;
8534 }
8535
8536 pce_info_use = NULL;
8537 pinfo->unit_num = INVALID_CE_INFO_UNIT_NUM;
8538 pinfo->num_ce_pipe_entries = 0;
8539 for (i = 0; i < MAX_CE_PIPE_PAIR_PER_UNIT; i++)
8540 pinfo->ce_pipe_entry[i].valid = 0;
8541
8542 for (i = 0; i < total; i++) {
8543
8544 if (p->alloc && !memcmp(p->handle,
8545 pinfo->handle, MAX_CE_INFO_HANDLE_SIZE)) {
8546 pce_info_use = p;
8547 found = true;
8548 break;
8549 }
8550 p++;
8551 }
8552 if (!pce_info_use)
8553 goto out;
8554 pinfo->unit_num = pce_info_use->unit_num;
8555 if (pce_info_use->num_ce_pipe_entries >
8556 MAX_CE_PIPE_PAIR_PER_UNIT)
8557 entries = MAX_CE_PIPE_PAIR_PER_UNIT;
8558 else
8559 entries = pce_info_use->num_ce_pipe_entries;
8560 pinfo->num_ce_pipe_entries = entries;
8561 pce_entry = pce_info_use->ce_pipe_entry;
8562 for (i = 0; i < entries; i++, pce_entry++)
8563 pinfo->ce_pipe_entry[i] = *pce_entry;
8564 for (; i < MAX_CE_PIPE_PAIR_PER_UNIT; i++)
8565 pinfo->ce_pipe_entry[i].valid = 0;
8566out:
8567 if (copy_to_user(argp, pinfo, sizeof(struct qseecom_ce_info_req))) {
8568 pr_err("copy_to_user failed\n");
8569 ret = -EFAULT;
8570 }
8571 return ret;
8572}
8573
8574/*
8575 * Check whitelist feature, and if TZ feature version is < 1.0.0,
8576 * then whitelist feature is not supported.
8577 */
8578static int qseecom_check_whitelist_feature(void)
8579{
8580 int version = scm_get_feat_version(FEATURE_ID_WHITELIST);
8581
8582 return version >= MAKE_WHITELIST_VERSION(1, 0, 0);
8583}
8584
8585static int qseecom_probe(struct platform_device *pdev)
8586{
8587 int rc;
8588 int i;
8589 uint32_t feature = 10;
8590 struct device *class_dev;
8591 struct msm_bus_scale_pdata *qseecom_platform_support = NULL;
8592 struct qseecom_command_scm_resp resp;
8593 struct qseecom_ce_info_use *pce_info_use = NULL;
8594
8595 qseecom.qsee_bw_count = 0;
8596 qseecom.qsee_perf_client = 0;
8597 qseecom.qsee_sfpb_bw_count = 0;
8598
8599 qseecom.qsee.ce_core_clk = NULL;
8600 qseecom.qsee.ce_clk = NULL;
8601 qseecom.qsee.ce_core_src_clk = NULL;
8602 qseecom.qsee.ce_bus_clk = NULL;
8603
8604 qseecom.cumulative_mode = 0;
8605 qseecom.current_mode = INACTIVE;
8606 qseecom.support_bus_scaling = false;
8607 qseecom.support_fde = false;
8608 qseecom.support_pfe = false;
8609
8610 qseecom.ce_drv.ce_core_clk = NULL;
8611 qseecom.ce_drv.ce_clk = NULL;
8612 qseecom.ce_drv.ce_core_src_clk = NULL;
8613 qseecom.ce_drv.ce_bus_clk = NULL;
8614 atomic_set(&qseecom.qseecom_state, QSEECOM_STATE_NOT_READY);
8615
8616 qseecom.app_block_ref_cnt = 0;
8617 init_waitqueue_head(&qseecom.app_block_wq);
8618 qseecom.whitelist_support = true;
8619
8620 rc = alloc_chrdev_region(&qseecom_device_no, 0, 1, QSEECOM_DEV);
8621 if (rc < 0) {
8622 pr_err("alloc_chrdev_region failed %d\n", rc);
8623 return rc;
8624 }
8625
8626 driver_class = class_create(THIS_MODULE, QSEECOM_DEV);
8627 if (IS_ERR(driver_class)) {
8628 rc = -ENOMEM;
8629 pr_err("class_create failed %d\n", rc);
8630 goto exit_unreg_chrdev_region;
8631 }
8632
8633 class_dev = device_create(driver_class, NULL, qseecom_device_no, NULL,
8634 QSEECOM_DEV);
8635 if (IS_ERR(class_dev)) {
8636 pr_err("class_device_create failed %d\n", rc);
8637 rc = -ENOMEM;
8638 goto exit_destroy_class;
8639 }
8640
8641 cdev_init(&qseecom.cdev, &qseecom_fops);
8642 qseecom.cdev.owner = THIS_MODULE;
8643
8644 rc = cdev_add(&qseecom.cdev, MKDEV(MAJOR(qseecom_device_no), 0), 1);
8645 if (rc < 0) {
8646 pr_err("cdev_add failed %d\n", rc);
8647 goto exit_destroy_device;
8648 }
8649
8650 INIT_LIST_HEAD(&qseecom.registered_listener_list_head);
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07008651 INIT_LIST_HEAD(&qseecom.registered_app_list_head);
8652 spin_lock_init(&qseecom.registered_app_list_lock);
Zhen Kongbcdeda22018-11-16 13:50:51 -08008653 INIT_LIST_HEAD(&qseecom.unregister_lsnr_pending_list_head);
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07008654 INIT_LIST_HEAD(&qseecom.registered_kclient_list_head);
8655 spin_lock_init(&qseecom.registered_kclient_list_lock);
8656 init_waitqueue_head(&qseecom.send_resp_wq);
Zhen Kongbcdeda22018-11-16 13:50:51 -08008657 init_waitqueue_head(&qseecom.register_lsnr_pending_wq);
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07008658 qseecom.send_resp_flag = 0;
8659
8660 qseecom.qsee_version = QSEEE_VERSION_00;
8661 rc = qseecom_scm_call(6, 3, &feature, sizeof(feature),
8662 &resp, sizeof(resp));
8663 pr_info("qseecom.qsee_version = 0x%x\n", resp.result);
8664 if (rc) {
8665 pr_err("Failed to get QSEE version info %d\n", rc);
8666 goto exit_del_cdev;
8667 }
8668 qseecom.qsee_version = resp.result;
8669 qseecom.qseos_version = QSEOS_VERSION_14;
8670 qseecom.commonlib_loaded = false;
8671 qseecom.commonlib64_loaded = false;
8672 qseecom.pdev = class_dev;
8673 /* Create ION msm client */
8674 qseecom.ion_clnt = msm_ion_client_create("qseecom-kernel");
8675 if (IS_ERR_OR_NULL(qseecom.ion_clnt)) {
8676 pr_err("Ion client cannot be created\n");
8677 rc = -ENOMEM;
8678 goto exit_del_cdev;
8679 }
8680
8681 /* register client for bus scaling */
8682 if (pdev->dev.of_node) {
8683 qseecom.pdev->of_node = pdev->dev.of_node;
8684 qseecom.support_bus_scaling =
8685 of_property_read_bool((&pdev->dev)->of_node,
8686 "qcom,support-bus-scaling");
8687 rc = qseecom_retrieve_ce_data(pdev);
8688 if (rc)
8689 goto exit_destroy_ion_client;
8690 qseecom.appsbl_qseecom_support =
8691 of_property_read_bool((&pdev->dev)->of_node,
8692 "qcom,appsbl-qseecom-support");
8693 pr_debug("qseecom.appsbl_qseecom_support = 0x%x",
8694 qseecom.appsbl_qseecom_support);
8695
8696 qseecom.commonlib64_loaded =
8697 of_property_read_bool((&pdev->dev)->of_node,
8698 "qcom,commonlib64-loaded-by-uefi");
8699 pr_debug("qseecom.commonlib64-loaded-by-uefi = 0x%x",
8700 qseecom.commonlib64_loaded);
8701 qseecom.fde_key_size =
8702 of_property_read_bool((&pdev->dev)->of_node,
8703 "qcom,fde-key-size");
8704 qseecom.no_clock_support =
8705 of_property_read_bool((&pdev->dev)->of_node,
8706 "qcom,no-clock-support");
8707 if (!qseecom.no_clock_support) {
8708 pr_info("qseecom clocks handled by other subsystem\n");
8709 } else {
8710 pr_info("no-clock-support=0x%x",
8711 qseecom.no_clock_support);
8712 }
8713
8714 if (of_property_read_u32((&pdev->dev)->of_node,
8715 "qcom,qsee-reentrancy-support",
8716 &qseecom.qsee_reentrancy_support)) {
8717 pr_warn("qsee reentrancy support phase is not defined, setting to default 0\n");
8718 qseecom.qsee_reentrancy_support = 0;
8719 } else {
8720 pr_warn("qseecom.qsee_reentrancy_support = %d\n",
8721 qseecom.qsee_reentrancy_support);
8722 }
8723
Jiten Patela7bb1d52018-05-11 12:34:26 +05308724 qseecom.enable_key_wrap_in_ks =
8725 of_property_read_bool((&pdev->dev)->of_node,
8726 "qcom,enable-key-wrap-in-ks");
8727 if (qseecom.enable_key_wrap_in_ks) {
8728 pr_warn("qseecom.enable_key_wrap_in_ks = %d\n",
8729 qseecom.enable_key_wrap_in_ks);
8730 }
8731
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07008732 /*
8733 * The qseecom bus scaling flag can not be enabled when
8734 * crypto clock is not handled by HLOS.
8735 */
8736 if (qseecom.no_clock_support && qseecom.support_bus_scaling) {
8737 pr_err("support_bus_scaling flag can not be enabled.\n");
8738 rc = -EINVAL;
8739 goto exit_destroy_ion_client;
8740 }
8741
8742 if (of_property_read_u32((&pdev->dev)->of_node,
8743 "qcom,ce-opp-freq",
8744 &qseecom.ce_opp_freq_hz)) {
8745 pr_debug("CE operating frequency is not defined, setting to default 100MHZ\n");
8746 qseecom.ce_opp_freq_hz = QSEE_CE_CLK_100MHZ;
8747 }
8748 rc = __qseecom_init_clk(CLK_QSEE);
8749 if (rc)
8750 goto exit_destroy_ion_client;
8751
8752 if ((qseecom.qsee.instance != qseecom.ce_drv.instance) &&
8753 (qseecom.support_pfe || qseecom.support_fde)) {
8754 rc = __qseecom_init_clk(CLK_CE_DRV);
8755 if (rc) {
8756 __qseecom_deinit_clk(CLK_QSEE);
8757 goto exit_destroy_ion_client;
8758 }
8759 } else {
8760 struct qseecom_clk *qclk;
8761
8762 qclk = &qseecom.qsee;
8763 qseecom.ce_drv.ce_core_clk = qclk->ce_core_clk;
8764 qseecom.ce_drv.ce_clk = qclk->ce_clk;
8765 qseecom.ce_drv.ce_core_src_clk = qclk->ce_core_src_clk;
8766 qseecom.ce_drv.ce_bus_clk = qclk->ce_bus_clk;
8767 }
8768
8769 qseecom_platform_support = (struct msm_bus_scale_pdata *)
8770 msm_bus_cl_get_pdata(pdev);
8771 if (qseecom.qsee_version >= (QSEE_VERSION_02) &&
8772 (!qseecom.is_apps_region_protected &&
8773 !qseecom.appsbl_qseecom_support)) {
8774 struct resource *resource = NULL;
8775 struct qsee_apps_region_info_ireq req;
8776 struct qsee_apps_region_info_64bit_ireq req_64bit;
8777 struct qseecom_command_scm_resp resp;
8778 void *cmd_buf = NULL;
8779 size_t cmd_len;
8780
8781 resource = platform_get_resource_byname(pdev,
8782 IORESOURCE_MEM, "secapp-region");
8783 if (resource) {
8784 if (qseecom.qsee_version < QSEE_VERSION_40) {
8785 req.qsee_cmd_id =
8786 QSEOS_APP_REGION_NOTIFICATION;
8787 req.addr = (uint32_t)resource->start;
8788 req.size = resource_size(resource);
8789 cmd_buf = (void *)&req;
8790 cmd_len = sizeof(struct
8791 qsee_apps_region_info_ireq);
8792 pr_warn("secure app region addr=0x%x size=0x%x",
8793 req.addr, req.size);
8794 } else {
8795 req_64bit.qsee_cmd_id =
8796 QSEOS_APP_REGION_NOTIFICATION;
8797 req_64bit.addr = resource->start;
8798 req_64bit.size = resource_size(
8799 resource);
8800 cmd_buf = (void *)&req_64bit;
8801 cmd_len = sizeof(struct
8802 qsee_apps_region_info_64bit_ireq);
8803 pr_warn("secure app region addr=0x%llx size=0x%x",
8804 req_64bit.addr, req_64bit.size);
8805 }
8806 } else {
8807 pr_err("Fail to get secure app region info\n");
8808 rc = -EINVAL;
8809 goto exit_deinit_clock;
8810 }
8811 rc = __qseecom_enable_clk(CLK_QSEE);
8812 if (rc) {
8813 pr_err("CLK_QSEE enabling failed (%d)\n", rc);
8814 rc = -EIO;
8815 goto exit_deinit_clock;
8816 }
8817 rc = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1,
8818 cmd_buf, cmd_len,
8819 &resp, sizeof(resp));
8820 __qseecom_disable_clk(CLK_QSEE);
8821 if (rc || (resp.result != QSEOS_RESULT_SUCCESS)) {
8822 pr_err("send secapp reg fail %d resp.res %d\n",
8823 rc, resp.result);
8824 rc = -EINVAL;
8825 goto exit_deinit_clock;
8826 }
8827 }
8828 /*
8829 * By default, appsbl only loads cmnlib. If OEM changes appsbl to
8830 * load cmnlib64 too, while cmnlib64 img is not present in non_hlos.bin,
8831 * Pls add "qseecom.commonlib64_loaded = true" here too.
8832 */
8833 if (qseecom.is_apps_region_protected ||
8834 qseecom.appsbl_qseecom_support)
8835 qseecom.commonlib_loaded = true;
8836 } else {
8837 qseecom_platform_support = (struct msm_bus_scale_pdata *)
8838 pdev->dev.platform_data;
8839 }
8840 if (qseecom.support_bus_scaling) {
8841 init_timer(&(qseecom.bw_scale_down_timer));
8842 INIT_WORK(&qseecom.bw_inactive_req_ws,
8843 qseecom_bw_inactive_req_work);
8844 qseecom.bw_scale_down_timer.function =
8845 qseecom_scale_bus_bandwidth_timer_callback;
8846 }
8847 qseecom.timer_running = false;
8848 qseecom.qsee_perf_client = msm_bus_scale_register_client(
8849 qseecom_platform_support);
8850
8851 qseecom.whitelist_support = qseecom_check_whitelist_feature();
8852 pr_warn("qseecom.whitelist_support = %d\n",
8853 qseecom.whitelist_support);
8854
8855 if (!qseecom.qsee_perf_client)
8856 pr_err("Unable to register bus client\n");
8857
8858 atomic_set(&qseecom.qseecom_state, QSEECOM_STATE_READY);
8859 return 0;
8860
8861exit_deinit_clock:
8862 __qseecom_deinit_clk(CLK_QSEE);
8863 if ((qseecom.qsee.instance != qseecom.ce_drv.instance) &&
8864 (qseecom.support_pfe || qseecom.support_fde))
8865 __qseecom_deinit_clk(CLK_CE_DRV);
8866exit_destroy_ion_client:
8867 if (qseecom.ce_info.fde) {
8868 pce_info_use = qseecom.ce_info.fde;
8869 for (i = 0; i < qseecom.ce_info.num_fde; i++) {
8870 kzfree(pce_info_use->ce_pipe_entry);
8871 pce_info_use++;
8872 }
8873 kfree(qseecom.ce_info.fde);
8874 }
8875 if (qseecom.ce_info.pfe) {
8876 pce_info_use = qseecom.ce_info.pfe;
8877 for (i = 0; i < qseecom.ce_info.num_pfe; i++) {
8878 kzfree(pce_info_use->ce_pipe_entry);
8879 pce_info_use++;
8880 }
8881 kfree(qseecom.ce_info.pfe);
8882 }
8883 ion_client_destroy(qseecom.ion_clnt);
8884exit_del_cdev:
8885 cdev_del(&qseecom.cdev);
8886exit_destroy_device:
8887 device_destroy(driver_class, qseecom_device_no);
8888exit_destroy_class:
8889 class_destroy(driver_class);
8890exit_unreg_chrdev_region:
8891 unregister_chrdev_region(qseecom_device_no, 1);
8892 return rc;
8893}
8894
8895static int qseecom_remove(struct platform_device *pdev)
8896{
8897 struct qseecom_registered_kclient_list *kclient = NULL;
Monika Singhe711b162018-04-24 09:54:50 +05308898 struct qseecom_registered_kclient_list *kclient_tmp = NULL;
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07008899 unsigned long flags = 0;
8900 int ret = 0;
8901 int i;
8902 struct qseecom_ce_pipe_entry *pce_entry;
8903 struct qseecom_ce_info_use *pce_info_use;
8904
8905 atomic_set(&qseecom.qseecom_state, QSEECOM_STATE_NOT_READY);
8906 spin_lock_irqsave(&qseecom.registered_kclient_list_lock, flags);
8907
Monika Singhe711b162018-04-24 09:54:50 +05308908 list_for_each_entry_safe(kclient, kclient_tmp,
8909 &qseecom.registered_kclient_list_head, list) {
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07008910
8911 /* Break the loop if client handle is NULL */
Zhen Kong9131def2018-07-13 12:02:32 -07008912 if (!kclient->handle) {
8913 list_del(&kclient->list);
8914 kzfree(kclient);
8915 break;
8916 }
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07008917
8918 list_del(&kclient->list);
8919 mutex_lock(&app_access_lock);
8920 ret = qseecom_unload_app(kclient->handle->dev, false);
8921 mutex_unlock(&app_access_lock);
8922 if (!ret) {
8923 kzfree(kclient->handle->dev);
8924 kzfree(kclient->handle);
8925 kzfree(kclient);
8926 }
8927 }
8928
AnilKumar Chimata20c6b2f2017-04-07 12:18:46 -07008929 spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock, flags);
8930
8931 if (qseecom.qseos_version > QSEEE_VERSION_00)
8932 qseecom_unload_commonlib_image();
8933
8934 if (qseecom.qsee_perf_client)
8935 msm_bus_scale_client_update_request(qseecom.qsee_perf_client,
8936 0);
8937 if (pdev->dev.platform_data != NULL)
8938 msm_bus_scale_unregister_client(qseecom.qsee_perf_client);
8939
8940 if (qseecom.support_bus_scaling) {
8941 cancel_work_sync(&qseecom.bw_inactive_req_ws);
8942 del_timer_sync(&qseecom.bw_scale_down_timer);
8943 }
8944
8945 if (qseecom.ce_info.fde) {
8946 pce_info_use = qseecom.ce_info.fde;
8947 for (i = 0; i < qseecom.ce_info.num_fde; i++) {
8948 pce_entry = pce_info_use->ce_pipe_entry;
8949 kfree(pce_entry);
8950 pce_info_use++;
8951 }
8952 }
8953 kfree(qseecom.ce_info.fde);
8954 if (qseecom.ce_info.pfe) {
8955 pce_info_use = qseecom.ce_info.pfe;
8956 for (i = 0; i < qseecom.ce_info.num_pfe; i++) {
8957 pce_entry = pce_info_use->ce_pipe_entry;
8958 kfree(pce_entry);
8959 pce_info_use++;
8960 }
8961 }
8962 kfree(qseecom.ce_info.pfe);
8963
8964 /* register client for bus scaling */
8965 if (pdev->dev.of_node) {
8966 __qseecom_deinit_clk(CLK_QSEE);
8967 if ((qseecom.qsee.instance != qseecom.ce_drv.instance) &&
8968 (qseecom.support_pfe || qseecom.support_fde))
8969 __qseecom_deinit_clk(CLK_CE_DRV);
8970 }
8971
8972 ion_client_destroy(qseecom.ion_clnt);
8973
8974 cdev_del(&qseecom.cdev);
8975
8976 device_destroy(driver_class, qseecom_device_no);
8977
8978 class_destroy(driver_class);
8979
8980 unregister_chrdev_region(qseecom_device_no, 1);
8981
8982 return ret;
8983}
8984
8985static int qseecom_suspend(struct platform_device *pdev, pm_message_t state)
8986{
8987 int ret = 0;
8988 struct qseecom_clk *qclk;
8989
8990 qclk = &qseecom.qsee;
8991 atomic_set(&qseecom.qseecom_state, QSEECOM_STATE_SUSPEND);
8992 if (qseecom.no_clock_support)
8993 return 0;
8994
8995 mutex_lock(&qsee_bw_mutex);
8996 mutex_lock(&clk_access_lock);
8997
8998 if (qseecom.current_mode != INACTIVE) {
8999 ret = msm_bus_scale_client_update_request(
9000 qseecom.qsee_perf_client, INACTIVE);
9001 if (ret)
9002 pr_err("Fail to scale down bus\n");
9003 else
9004 qseecom.current_mode = INACTIVE;
9005 }
9006
9007 if (qclk->clk_access_cnt) {
9008 if (qclk->ce_clk != NULL)
9009 clk_disable_unprepare(qclk->ce_clk);
9010 if (qclk->ce_core_clk != NULL)
9011 clk_disable_unprepare(qclk->ce_core_clk);
9012 if (qclk->ce_bus_clk != NULL)
9013 clk_disable_unprepare(qclk->ce_bus_clk);
9014 }
9015
9016 del_timer_sync(&(qseecom.bw_scale_down_timer));
9017 qseecom.timer_running = false;
9018
9019 mutex_unlock(&clk_access_lock);
9020 mutex_unlock(&qsee_bw_mutex);
9021 cancel_work_sync(&qseecom.bw_inactive_req_ws);
9022
9023 return 0;
9024}
9025
9026static int qseecom_resume(struct platform_device *pdev)
9027{
9028 int mode = 0;
9029 int ret = 0;
9030 struct qseecom_clk *qclk;
9031
9032 qclk = &qseecom.qsee;
9033 if (qseecom.no_clock_support)
9034 goto exit;
9035
9036 mutex_lock(&qsee_bw_mutex);
9037 mutex_lock(&clk_access_lock);
9038 if (qseecom.cumulative_mode >= HIGH)
9039 mode = HIGH;
9040 else
9041 mode = qseecom.cumulative_mode;
9042
9043 if (qseecom.cumulative_mode != INACTIVE) {
9044 ret = msm_bus_scale_client_update_request(
9045 qseecom.qsee_perf_client, mode);
9046 if (ret)
9047 pr_err("Fail to scale up bus to %d\n", mode);
9048 else
9049 qseecom.current_mode = mode;
9050 }
9051
9052 if (qclk->clk_access_cnt) {
9053 if (qclk->ce_core_clk != NULL) {
9054 ret = clk_prepare_enable(qclk->ce_core_clk);
9055 if (ret) {
9056 pr_err("Unable to enable/prep CE core clk\n");
9057 qclk->clk_access_cnt = 0;
9058 goto err;
9059 }
9060 }
9061 if (qclk->ce_clk != NULL) {
9062 ret = clk_prepare_enable(qclk->ce_clk);
9063 if (ret) {
9064 pr_err("Unable to enable/prep CE iface clk\n");
9065 qclk->clk_access_cnt = 0;
9066 goto ce_clk_err;
9067 }
9068 }
9069 if (qclk->ce_bus_clk != NULL) {
9070 ret = clk_prepare_enable(qclk->ce_bus_clk);
9071 if (ret) {
9072 pr_err("Unable to enable/prep CE bus clk\n");
9073 qclk->clk_access_cnt = 0;
9074 goto ce_bus_clk_err;
9075 }
9076 }
9077 }
9078
9079 if (qclk->clk_access_cnt || qseecom.cumulative_mode) {
9080 qseecom.bw_scale_down_timer.expires = jiffies +
9081 msecs_to_jiffies(QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
9082 mod_timer(&(qseecom.bw_scale_down_timer),
9083 qseecom.bw_scale_down_timer.expires);
9084 qseecom.timer_running = true;
9085 }
9086
9087 mutex_unlock(&clk_access_lock);
9088 mutex_unlock(&qsee_bw_mutex);
9089 goto exit;
9090
9091ce_bus_clk_err:
9092 if (qclk->ce_clk)
9093 clk_disable_unprepare(qclk->ce_clk);
9094ce_clk_err:
9095 if (qclk->ce_core_clk)
9096 clk_disable_unprepare(qclk->ce_core_clk);
9097err:
9098 mutex_unlock(&clk_access_lock);
9099 mutex_unlock(&qsee_bw_mutex);
9100 ret = -EIO;
9101exit:
9102 atomic_set(&qseecom.qseecom_state, QSEECOM_STATE_READY);
9103 return ret;
9104}
9105
9106static const struct of_device_id qseecom_match[] = {
9107 {
9108 .compatible = "qcom,qseecom",
9109 },
9110 {}
9111};
9112
9113static struct platform_driver qseecom_plat_driver = {
9114 .probe = qseecom_probe,
9115 .remove = qseecom_remove,
9116 .suspend = qseecom_suspend,
9117 .resume = qseecom_resume,
9118 .driver = {
9119 .name = "qseecom",
9120 .owner = THIS_MODULE,
9121 .of_match_table = qseecom_match,
9122 },
9123};
9124
9125static int qseecom_init(void)
9126{
9127 return platform_driver_register(&qseecom_plat_driver);
9128}
9129
9130static void qseecom_exit(void)
9131{
9132 platform_driver_unregister(&qseecom_plat_driver);
9133}
9134
9135MODULE_LICENSE("GPL v2");
9136MODULE_DESCRIPTION("QTI Secure Execution Environment Communicator");
9137
9138module_init(qseecom_init);
9139module_exit(qseecom_exit);