diff options
author | rthavti <quic_rthavti@quicinc.com> | 2023-01-27 18:32:10 +0530 |
---|---|---|
committer | rthavti <quic_rthavti@quicinc.com> | 2023-01-27 18:32:10 +0530 |
commit | 8e601de94bc895ab77c27890347ca04d15a24b4a (patch) | |
tree | 4e2942dc614c5d7ca4f44e5f43476b38aea73e39 | |
parent | 55d4cd3ca27291ade75309ac3cfe28cd7000dc8e (diff) | |
parent | 0e92ea4387f8c0a4d295b10dfa07f7155455ab84 (diff) | |
download | securemsm-8e601de94bc895ab77c27890347ca04d15a24b4a.tar.gz |
Merge commit '0e92ea4387f8c0a4d295b10dfa07f7155455ab84' into sec-kernel.lnx.13.1.r9-rel
Change-Id: I8ff4752aab38ed594dabb1539bbe250653d0ce7a
-rw-r--r-- | Kbuild | 7 | ||||
-rw-r--r-- | crypto-qti/qce.h | 11 | ||||
-rw-r--r-- | crypto-qti/qce50.c | 100 | ||||
-rw-r--r-- | crypto-qti/qce50.h | 1 | ||||
-rw-r--r-- | crypto-qti/qcedev.c | 88 | ||||
-rw-r--r-- | qseecom/qseecom.c | 261 | ||||
-rw-r--r-- | qseecom/qseecom_32bit_impl.c | 943 | ||||
-rw-r--r-- | qseecom/qseecom_32bit_impl.h | 341 | ||||
-rw-r--r-- | securemsm_kernel_vendor_board.mk | 4 | ||||
-rw-r--r-- | smcinvoke/IClientEnv.h | 13 | ||||
-rw-r--r-- | smcinvoke/smcinvoke.c | 90 | ||||
-rw-r--r-- | smcinvoke/smcinvoke_kernel.c | 11 | ||||
-rw-r--r-- | smcinvoke/smcinvoke_object.h | 1 |
13 files changed, 1724 insertions, 147 deletions
@@ -7,12 +7,15 @@ ifneq ($(CONFIG_ARCH_QTI_VM), y) endif #Enable Qseecom if CONFIG_ARCH_KHAJE OR CONFIG_ARCH_KHAJE or CONFIG_QTI_QUIN_GVM or CONFIG_ARCH_MONACO or CONFIG_ARCH_SCUBA_AUTO or CONFIG_ARCH_SA410M is set to y -ifneq (, $(filter y, $(CONFIG_QTI_QUIN_GVM) $(CONFIG_ARCH_KHAJE) $(CONFIG_ARCH_SA8155) $(CONFIG_ARCH_MONACO) $(CONFIG_ARCH_SCUBA_AUTO) $(CONFIG_ARCH_SA410M))) +ifneq (, $(filter y, $(CONFIG_QTI_QUIN_GVM) $(CONFIG_ARCH_KHAJE) $(CONFIG_ARCH_SA8155) $(CONFIG_ARCH_LEMANS) $(CONFIG_ARCH_MONACO) $(CONFIG_ARCH_SCUBA_AUTO) $(CONFIG_ARCH_SA410M))) include $(SSG_MODULE_ROOT)/config/sec-kernel_defconfig_qseecom.conf LINUXINCLUDE += -include $(SSG_MODULE_ROOT)/config/sec-kernel_defconfig_qseecom.h obj-$(CONFIG_QSEECOM) += qseecom_dlkm.o - qseecom_dlkm-objs := qseecom/qseecom.o qseecom/compat_qseecom.o + qseecom_dlkm-objs := qseecom/qseecom.o + ifdef CONFIG_COMPAT + qseecom_dlkm-objs += qseecom/qseecom_32bit_impl.o + endif endif include $(SSG_MODULE_ROOT)/config/sec-kernel_defconfig_smcinvoke.conf diff --git a/crypto-qti/qce.h b/crypto-qti/qce.h index f461924..6d6f6ff 100644 --- a/crypto-qti/qce.h +++ b/crypto-qti/qce.h @@ -198,6 +198,13 @@ struct qce_pm_table { extern struct qce_pm_table qce_pm_table; +struct qce_error { + bool no_error; + bool timer_error; + bool key_paused; + bool generic_error; +}; + void *qce_open(struct platform_device *pdev, int *rc); int qce_close(void *handle); int qce_aead_req(void *handle, struct qce_req *req); @@ -209,9 +216,7 @@ int qce_disable_clk(void *handle); void qce_get_driver_stats(void *handle); void qce_clear_driver_stats(void *handle); void qce_dump_req(void *handle); -void qce_get_crypto_status(void *handle, unsigned int *s1, unsigned int *s2, - unsigned int *s3, unsigned int *s4, - unsigned int *s5, unsigned int *s6); +void qce_get_crypto_status(void *handle, struct qce_error *error); int qce_manage_timeout(void *handle, int req_info); int qce_set_irqs(void *handle, bool enable); #endif /* __CRYPTO_MSM_QCE_H */ diff --git a/crypto-qti/qce50.c b/crypto-qti/qce50.c index d6a762f..0521ed6 100644 --- a/crypto-qti/qce50.c +++ b/crypto-qti/qce50.c @@ -85,7 +85,26 @@ static LIST_HEAD(qce50_bam_list); #define TOTAL_IOVEC_SPACE_PER_PIPE (QCE_MAX_NUM_DSCR * sizeof(struct sps_iovec)) #define AES_CTR_IV_CTR_SIZE 64 -#define STATUS1_ERR_INTR_MASK 0x10 + +#define QCE_STATUS1_NO_ERROR 0x2000006 + +// Crypto Engines 5.7 and below +// Key timer expiry for pipes 1-15 (Status3) +#define CRYPTO5_LEGACY_TIMER_EXPIRED_STATUS3 0x0000FF00 +// Key timer expiry for pipes 16-19 (Status6) +#define CRYPTO5_LEGACY_TIMER_EXPIRED_STATUS6 0x00000300 +// Key pause for pipes 1-15 (Status3) +#define CRYPTO5_LEGACY_KEY_PAUSE_STATUS3 0xFF000000 +// Key pause for pipes 16-19 (Status6) +#define CRYPTO5_LEGACY_KEY_PAUSE_STATUS6 0x3000000 + +// Crypto Engines 5.8 and above +// Key timer expiry for all pipes (Status3) +#define CRYPTO58_TIMER_EXPIRED 0x00000010 +// Key pause for all pipes (Status3) +#define CRYPTO58_KEY_PAUSE 0x00001000 +// Key index for Status3 (Timer and Key Pause) +#define KEY_INDEX_SHIFT 16 enum qce_owner { QCE_OWNER_NONE = 0, @@ -201,36 +220,72 @@ static uint32_t qce_get_config_be(struct qce_device *pce_dev, pipe_pair << CRYPTO_PIPE_SET_SELECT); } -static void dump_status_regs(unsigned int s1, unsigned int s2,unsigned int s3, - unsigned int s4, unsigned int s5,unsigned int s6) +static void dump_status_regs(unsigned int *status) { - pr_info("%s: CRYPTO_STATUS_REG = 0x%x\n", __func__, s1); - pr_info("%s: CRYPTO_STATUS2_REG = 0x%x\n", __func__, s2); - pr_info("%s: CRYPTO_STATUS3_REG = 0x%x\n", __func__, s3); - pr_info("%s: CRYPTO_STATUS4_REG = 0x%x\n", __func__, s4); - pr_info("%s: CRYPTO_STATUS5_REG = 0x%x\n", __func__, s5); - pr_info("%s: CRYPTO_STATUS6_REG = 0x%x\n", __func__, s6); + pr_info("%s: CRYPTO_STATUS_REG = 0x%x\n", __func__, status[0]); + pr_info("%s: CRYPTO_STATUS2_REG = 0x%x\n", __func__, status[1]); + pr_info("%s: CRYPTO_STATUS3_REG = 0x%x\n", __func__, status[2]); + pr_info("%s: CRYPTO_STATUS4_REG = 0x%x\n", __func__, status[3]); + pr_info("%s: CRYPTO_STATUS5_REG = 0x%x\n", __func__, status[4]); + pr_info("%s: CRYPTO_STATUS6_REG = 0x%x\n", __func__, status[5]); } -void qce_get_crypto_status(void *handle, unsigned int *s1, unsigned int *s2, - unsigned int *s3, unsigned int *s4, - unsigned int *s5, unsigned int *s6) +void qce_get_crypto_status(void *handle, struct qce_error *error) { struct qce_device *pce_dev = (struct qce_device *) handle; + unsigned int status[6] = {0}; - *s1 = readl_relaxed(pce_dev->iobase + CRYPTO_STATUS_REG); - *s2 = readl_relaxed(pce_dev->iobase + CRYPTO_STATUS2_REG); - *s3 = readl_relaxed(pce_dev->iobase + CRYPTO_STATUS3_REG); - *s4 = readl_relaxed(pce_dev->iobase + CRYPTO_STATUS4_REG); - *s5 = readl_relaxed(pce_dev->iobase + CRYPTO_STATUS5_REG); - *s6 = readl_relaxed(pce_dev->iobase + CRYPTO_STATUS6_REG); + status[0] = readl_relaxed(pce_dev->iobase + CRYPTO_STATUS_REG); + status[1] = readl_relaxed(pce_dev->iobase + CRYPTO_STATUS2_REG); + status[2] = readl_relaxed(pce_dev->iobase + CRYPTO_STATUS3_REG); + status[3] = readl_relaxed(pce_dev->iobase + CRYPTO_STATUS4_REG); + status[4] = readl_relaxed(pce_dev->iobase + CRYPTO_STATUS5_REG); + status[5] = readl_relaxed(pce_dev->iobase + CRYPTO_STATUS6_REG); #ifdef QCE_DEBUG - dump_status_regs(*s1, *s2, *s3, *s4, *s5, *s6); -#else - if (*s1 & STATUS1_ERR_INTR_MASK) - dump_status_regs(*s1, *s2, *s3, *s4, *s5, *s6); + dump_status_regs(&status[0]); #endif + + if (status[0] == QCE_STATUS1_NO_ERROR) { + error->no_error = true; + pr_err("%s: No crypto error, status1 = 0x%x\n", + __func__, status[0]); + } else { + if (pce_dev->ce_bam_info.minor_version >= 8) { + if (status[2] & CRYPTO58_TIMER_EXPIRED) { + error->timer_error = true; + pr_err("%s: timer expired, index = 0x%x\n", + __func__, (status[2] >> KEY_INDEX_SHIFT)); + } else if (status[2] & CRYPTO58_KEY_PAUSE) { + error->key_paused = true; + pr_err("%s: key paused, index = 0x%x\n", + __func__, (status[2] >> KEY_INDEX_SHIFT)); + } else { + pr_err("%s: generic error, refer all status\n", + __func__); + error->generic_error = true; + } + } else { + if ((status[2] & CRYPTO5_LEGACY_TIMER_EXPIRED_STATUS3) || + (status[5] & CRYPTO5_LEGACY_TIMER_EXPIRED_STATUS6)) { + error->timer_error = true; + pr_err("%s: timer expired, refer status 3 and 6\n", + __func__); + } + else if ((status[2] & CRYPTO5_LEGACY_KEY_PAUSE_STATUS3) || + (status[5] & CRYPTO5_LEGACY_KEY_PAUSE_STATUS6)) { + error->key_paused = true; + pr_err("%s: key paused, reder status 3 and 6\n", + __func__); + } else { + pr_err("%s: generic error, refer all status\n", + __func__); + error->generic_error = true; + } + } + dump_status_regs(&status[0]); + } + return; } EXPORT_SYMBOL(qce_get_crypto_status); @@ -414,6 +469,7 @@ static int _probe_ce_engine(struct qce_device *pce_dev) pce_dev->no_ccm_mac_status_get_around = false; pce_dev->ce_bam_info.minor_version = min_rev; + pce_dev->ce_bam_info.major_version = maj_rev; pce_dev->engines_avail = readl_relaxed(pce_dev->iobase + CRYPTO_ENGINES_AVAIL); diff --git a/crypto-qti/qce50.h b/crypto-qti/qce50.h index e679df0..c8df639 100644 --- a/crypto-qti/qce50.h +++ b/crypto-qti/qce50.h @@ -200,6 +200,7 @@ struct ce_bam_info { unsigned long bam_handle; int ce_burst_size; uint32_t minor_version; + uint32_t major_version; struct qce_sps_ep_conn_data producer[QCE_OFFLOAD_OPER_LAST]; struct qce_sps_ep_conn_data consumer[QCE_OFFLOAD_OPER_LAST]; }; diff --git a/crypto-qti/qcedev.c b/crypto-qti/qcedev.c index c7ef677..d1a238e 100644 --- a/crypto-qti/qcedev.c +++ b/crypto-qti/qcedev.c @@ -71,17 +71,6 @@ static uint8_t _std_init_vector_sha256_uint8[] = { #define QCEDEV_CTX_USE_HW_KEY 0x00000001 #define QCEDEV_CTX_USE_PIPE_KEY 0x00000002 -// Key timer expiry for pipes 1-15 (Status3) -#define PIPE_KEY_TIMER_EXPIRED_STATUS3_MASK 0x000000FF -// Key timer expiry for pipes 16-19 (Status6) -#define PIPE_KEY_TIMER_EXPIRED_STATUS6_MASK 0x00000003 -// Key pause for pipes 1-15 (Status3) -#define PIPE_KEY_PAUSE_STATUS3_MASK 0xFF0000 -// Key pause for pipes 16-19 (Status6) -#define PIPE_KEY_PAUSE_STATUS6_MASK 0x30000 - -#define QCEDEV_STATUS1_ERR_INTR_MASK 0x10 - static DEFINE_MUTEX(send_cmd_lock); static DEFINE_MUTEX(qcedev_sent_bw_req); static DEFINE_MUTEX(hash_access_lock); @@ -707,53 +696,29 @@ static int start_sha_req(struct qcedev_control *podev, }; static void qcedev_check_crypto_status( - struct qcedev_async_req *qcedev_areq, void *handle, - bool print_err) + struct qcedev_async_req *qcedev_areq, void *handle) { - unsigned int s1, s2, s3, s4, s5, s6; + struct qce_error error = {0}; qcedev_areq->offload_cipher_op_req.err = QCEDEV_OFFLOAD_NO_ERROR; - qce_get_crypto_status(handle, &s1, &s2, &s3, &s4, &s5, &s6); - - if (print_err) { - pr_err("%s: sts = 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", __func__, - s1, s2, s3, s4, s5, s6); - } + qce_get_crypto_status(handle, &error); - // Check for key timer expiry - if ((s6 & PIPE_KEY_TIMER_EXPIRED_STATUS6_MASK) || - (s3 & PIPE_KEY_TIMER_EXPIRED_STATUS3_MASK)) { - pr_info("%s: crypto timer expired\n", __func__); - pr_info("%s: sts = 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", __func__, - s1, s2, s3, s4, s5, s6); + if (error.timer_error) { qcedev_areq->offload_cipher_op_req.err = - QCEDEV_OFFLOAD_KEY_TIMER_EXPIRED_ERROR; - return; - } - - // Check for key pause - if ((s6 & PIPE_KEY_PAUSE_STATUS6_MASK) || - (s3 & PIPE_KEY_PAUSE_STATUS3_MASK)) { - pr_info("%s: crypto key paused\n", __func__); - pr_info("%s: sts = 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", __func__, - s1, s2, s3, s4, s5, s6); + QCEDEV_OFFLOAD_KEY_TIMER_EXPIRED_ERROR; + } else if (error.key_paused) { qcedev_areq->offload_cipher_op_req.err = - QCEDEV_OFFLOAD_KEY_PAUSE_ERROR; - return; - } - - // Check for generic error - if (s1 & QCEDEV_STATUS1_ERR_INTR_MASK) { - pr_err("%s: generic crypto error\n", __func__); - pr_info("%s: sts = 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", __func__, - s1, s2, s3, s4, s5, s6); + QCEDEV_OFFLOAD_KEY_PAUSE_ERROR; + } else if (error.generic_error) { qcedev_areq->offload_cipher_op_req.err = - QCEDEV_OFFLOAD_GENERIC_ERROR; - return; + QCEDEV_OFFLOAD_GENERIC_ERROR; } + + return; } -#define MAX_RETRIES 333 + +#define MAX_RETRIES 333 static int submit_req(struct qcedev_async_req *qcedev_areq, struct qcedev_handle *handle) @@ -764,7 +729,6 @@ static int submit_req(struct qcedev_async_req *qcedev_areq, struct qcedev_stat *pstat; int current_req_info = 0; int wait = MAX_CRYPTO_WAIT_TIME; - bool print_sts = false; struct qcedev_async_req *new_req = NULL; int retries = 0; int req_wait = MAX_REQUEST_TIME; @@ -773,7 +737,6 @@ static int submit_req(struct qcedev_async_req *qcedev_areq, podev = handle->cntl; init_waitqueue_head(&qcedev_areq->wait_q); - spin_lock_irqsave(&podev->lock, flags); /* @@ -852,25 +815,26 @@ static int submit_req(struct qcedev_async_req *qcedev_areq, */ pr_err("%s: wait timed out, req info = %d\n", __func__, current_req_info); - print_sts = true; - spin_lock_irqsave(&podev->lock, flags); - qcedev_check_crypto_status(qcedev_areq, podev->qce, print_sts); - qcedev_areq->timed_out = true; - ret = qce_manage_timeout(podev->qce, current_req_info); - spin_unlock_irqrestore(&podev->lock, flags); - if (ret) { - pr_err("%s: error during manage timeout", __func__); + qcedev_check_crypto_status(qcedev_areq, podev->qce); + if (qcedev_areq->offload_cipher_op_req.err == + QCEDEV_OFFLOAD_NO_ERROR) { + pr_err("%s: no error, wait for request to be done", __func__); while (qcedev_areq->state != QCEDEV_REQ_DONE && - retries < MAX_RETRIES) { + retries < MAX_RETRIES) { usleep_range(3000, 5000); retries++; pr_err("%s: waiting for req state to be done, retries = %d", - __func__, retries); + __func__, retries); } - // This means there is no crypto error, timeout corner case. - qcedev_areq->offload_cipher_op_req.err = QCEDEV_OFFLOAD_NO_ERROR; return 0; } + spin_lock_irqsave(&podev->lock, flags); + qcedev_areq->timed_out = true; + ret = qce_manage_timeout(podev->qce, current_req_info); + if (ret) + pr_err("%s: error during manage timeout", __func__); + + spin_unlock_irqrestore(&podev->lock, flags); tasklet_schedule(&podev->done_tasklet); if (qcedev_areq->offload_cipher_op_req.err != QCEDEV_OFFLOAD_NO_ERROR) diff --git a/qseecom/qseecom.c b/qseecom/qseecom.c index 8aac9c8..362f2b2 100644 --- a/qseecom/qseecom.c +++ b/qseecom/qseecom.c @@ -54,7 +54,7 @@ #include "misc/qseecom_kernel.h" #endif #if IS_ENABLED(CONFIG_COMPAT) -#include "compat_qseecom.h" +#include "qseecom_32bit_impl.h" #endif #define QSEECOM_DEV "qseecom" @@ -118,6 +118,25 @@ #define FDE_FLAG_POS 4 #define ENABLE_KEY_WRAP_IN_KS (1 << FDE_FLAG_POS) +#define K_COPY_FROM_USER(err, dst, src, size) \ + do {\ + if (!(CONFIG_COMPAT))\ + err = copy_from_user((dst),\ + (void const __user *)(src),\ + (size));\ + else\ + memmove((dst), (src), (size));\ + } while (0) + +#define K_COPY_TO_USER(err, dst, src, size) \ + do {\ + if(!(CONFIG_COMPAT))\ + err = copy_to_user((void __user *)(dst),\ + (src), (size));\ + else\ + memmove((dst), (src), (size));\ + } while (0) + enum qseecom_clk_definitions { CLK_DFAB = 0, CLK_SFPB, @@ -297,6 +316,7 @@ struct qseecom_control { bool whitelist_support; bool commonlib_loaded; bool commonlib64_loaded; + bool commonlib_loaded_by_hostvm; struct ce_hw_usage_info ce_info; int qsee_bw_count; @@ -1514,7 +1534,11 @@ static int qseecom_register_listener(struct qseecom_dev_handle *data, struct qseecom_registered_listener_list *new_entry; struct qseecom_registered_listener_list *ptr_svc; - memcpy(&rcvd_lstnr, argp, sizeof(rcvd_lstnr)); + K_COPY_FROM_USER(ret, &rcvd_lstnr, argp, sizeof(rcvd_lstnr)); + if (ret) { + pr_err("copy_from_user failed\n"); + return ret; + } if (!access_ok((void __user *)rcvd_lstnr.virt_sb_base, rcvd_lstnr.sb_size)) return -EFAULT; @@ -1925,7 +1949,11 @@ static int qseecom_scale_bus_bandwidth(struct qseecom_dev_handle *data, if (qseecom.no_clock_support) return 0; - memcpy(&req_mode, argp, sizeof(req_mode)); + K_COPY_FROM_USER(ret, &req_mode, argp, sizeof(req_mode)); + if (ret) { + pr_err("copy_from_user failed\n"); + return ret; + } if (req_mode > HIGH) { pr_err("Invalid bandwidth mode (%d)\n", req_mode); return -EINVAL; @@ -1998,12 +2026,14 @@ static int __qseecom_enable_clk_scale_up(struct qseecom_dev_handle *data) static int qseecom_set_client_mem_param(struct qseecom_dev_handle *data, void __user *argp) { - int32_t ret; + int32_t ret = 0; struct qseecom_set_sb_mem_param_req req; size_t len; /* Copy the relevant information needed for loading the image */ - memcpy(&req, (void __user *)argp, sizeof(req)); + K_COPY_FROM_USER(ret, &req, argp, sizeof(req)); + if(ret) + return -EFAULT; if ((req.ifd_data_fd <= 0) || (req.virt_sb_base == NULL) || (req.sb_len == 0)) { @@ -2751,11 +2781,16 @@ static int qseecom_load_app(struct qseecom_dev_handle *data, void __user *argp) bool first_time = false; /* Copy the relevant information needed for loading the image */ - memcpy(&load_img_req, (void __user *)argp, sizeof(struct qseecom_load_img_req)); - + K_COPY_FROM_USER(ret, &load_img_req, argp, + sizeof(struct qseecom_load_img_req)); + if(ret) { + pr_err("copy_from_user failed\n"); + return -EFAULT; + } /* Check and load cmnlib */ if (qseecom.qsee_version > QSEEE_VERSION_00) { - if (!qseecom.commonlib_loaded && + if (!(qseecom.commonlib_loaded || + qseecom.commonlib_loaded_by_hostvm) && load_img_req.app_arch == ELFCLASS32) { ret = qseecom_load_commonlib_image(data, "cmnlib"); if (ret) { @@ -2766,7 +2801,8 @@ static int qseecom_load_app(struct qseecom_dev_handle *data, void __user *argp) pr_debug("cmnlib is loaded\n"); } - if (!qseecom.commonlib64_loaded && + if (!(qseecom.commonlib64_loaded || + qseecom.commonlib_loaded_by_hostvm) && load_img_req.app_arch == ELFCLASS64) { ret = qseecom_load_commonlib_image(data, "cmnlib64"); if (ret) { @@ -2969,7 +3005,19 @@ static int qseecom_load_app(struct qseecom_dev_handle *data, void __user *argp) MAX_APP_NAME_SIZE); load_img_req.app_id = app_id; - memcpy(argp, &load_img_req, sizeof(load_img_req)); + K_COPY_TO_USER(ret, argp, &load_img_req, sizeof(load_img_req)); + if(ret) { + pr_err("copy_to_user failed\n"); + ret = -EFAULT; + if (first_time) { + spin_lock_irqsave( + &qseecom.registered_app_list_lock, flags); + list_del(&entry->list); + spin_unlock_irqrestore( + &qseecom.registered_app_list_lock, flags); + kfree_sensitive(entry); + } + } loadapp_err: if (dmabuf) { @@ -3424,8 +3472,12 @@ static int qseecom_send_service_cmd(struct qseecom_dev_handle *data, size_t req_buf_size; /*struct qseecom_command_scm_resp resp;*/ + K_COPY_FROM_USER(ret, &req, argp, sizeof(req)); + if(ret) { + pr_err("copy_from_user failed\n"); + return -EFAULT; + } - memcpy(&req, (void __user *)argp, sizeof(req)); if (__validate_send_service_cmd_inputs(data, &req)) return -EINVAL; @@ -3819,7 +3871,11 @@ static int qseecom_send_cmd(struct qseecom_dev_handle *data, void __user *argp) int ret = 0; struct qseecom_send_cmd_req req; - memcpy(&req, argp, sizeof(req)); + K_COPY_FROM_USER(ret, &req, argp, sizeof(req)); + if (ret) { + pr_err("copy_from_user failed\n"); + return ret; + } if (__validate_send_cmd_inputs(data, &req)) return -EINVAL; @@ -4312,7 +4368,11 @@ static int __qseecom_send_modfd_cmd(struct qseecom_dev_handle *data, phys_addr_t pa; u8 *va = NULL; - memcpy(&req, argp, sizeof(req)); + K_COPY_FROM_USER(ret, &req, argp, sizeof(req)); + if (ret) { + pr_err("copy_from_user failed\n"); + return ret; + } send_cmd_req.cmd_req_buf = req.cmd_req_buf; send_cmd_req.cmd_req_len = req.cmd_req_len; @@ -4703,7 +4763,9 @@ static int __qseecom_load_fw(struct qseecom_dev_handle *data, char *appname, /* Check and load cmnlib */ if (qseecom.qsee_version > QSEEE_VERSION_00) { - if (!qseecom.commonlib_loaded && app_arch == ELFCLASS32) { + if (!(qseecom.commonlib_loaded || + qseecom.commonlib_loaded_by_hostvm) && + app_arch == ELFCLASS32) { ret = qseecom_load_commonlib_image(data, "cmnlib"); if (ret) { pr_err("failed to load cmnlib\n"); @@ -4713,7 +4775,9 @@ static int __qseecom_load_fw(struct qseecom_dev_handle *data, char *appname, pr_debug("cmnlib is loaded\n"); } - if (!qseecom.commonlib64_loaded && app_arch == ELFCLASS64) { + if (!(qseecom.commonlib64_loaded || + qseecom.commonlib_loaded_by_hostvm) && + app_arch == ELFCLASS64) { ret = qseecom_load_commonlib_image(data, "cmnlib64"); if (ret) { pr_err("failed to load cmnlib64\n"); @@ -5246,8 +5310,10 @@ static int __qseecom_send_command(struct qseecom_handle *handle, void *send_buf, } perf_enabled = true; } - if (!strcmp(data->client.app_name, "securemm")) + if (!strcmp(data->client.app_name, "securemm") || + !strcmp(data->client.app_name, "slateapp")) { data->use_legacy_cmd = true; + } ret = __qseecom_send_cmd(data, &req, false); @@ -5470,8 +5536,14 @@ static int __qseecom_send_modfd_resp(struct qseecom_dev_handle *data, { struct qseecom_send_modfd_listener_resp resp; struct qseecom_registered_listener_list *this_lstnr = NULL; + int err = 0; + + K_COPY_FROM_USER(err, &resp, argp, sizeof(resp)); + if(err) { + pr_err("copy_from_user failed\n"); + return -EINVAL; + } - memcpy(&resp, argp, sizeof(resp)); this_lstnr = __qseecom_find_svc(data->listener.id); if (this_lstnr == NULL) return -EINVAL; @@ -5508,10 +5580,19 @@ static int qseecom_get_qseos_version(struct qseecom_dev_handle *data, void __user *argp) { struct qseecom_qseos_version_req req; + int err = 0; - memcpy(&req, argp, sizeof(req)); + K_COPY_FROM_USER(err, &req, argp, sizeof(req)); + if(err) { + pr_err("copy_from_user failed\n"); + return -EINVAL; + } req.qseos_version = qseecom.qseos_version; - memcpy(argp, &req, sizeof(req)); + K_COPY_TO_USER(err, argp, &req, sizeof(req)); + if(err) { + pr_err("copy_to_user failed\n"); + return -EINVAL; + } return 0; } @@ -5799,8 +5880,12 @@ static int qseecom_load_external_elf(struct qseecom_dev_handle *data, void *va = NULL; /* Copy the relevant information needed for loading the image */ - memcpy(&load_img_req, (void __user *)argp, sizeof(struct qseecom_load_img_req)); - + K_COPY_FROM_USER(ret, &load_img_req, argp, + sizeof(struct qseecom_load_img_req)); + if(ret) { + pr_err("copy_from_user failed\n"); + return -EFAULT; + } /* Get the handle of the shared fd */ ret = qseecom_vaddr_map(load_img_req.ifd_data_fd, &pa, &va, &sgt, &attach, &len, &dmabuf); @@ -5965,8 +6050,13 @@ static int qseecom_query_app_loaded(struct qseecom_dev_handle *data, bool found_app = false; /* Copy the relevant information needed for loading the image */ - memcpy(&query_req, (void __user *)argp, + K_COPY_FROM_USER(ret, &query_req, argp, sizeof(struct qseecom_qseos_app_load_query)); + if(ret) { + pr_err("copy_from_user failed\n"); + ret = -EFAULT; + goto exit_free; + } req.qsee_cmd_id = QSEOS_APP_LOOKUP_COMMAND; query_req.app_name[MAX_APP_NAME_SIZE-1] = '\0'; @@ -6039,7 +6129,12 @@ static int qseecom_query_app_loaded(struct qseecom_dev_handle *data, spin_unlock_irqrestore( &qseecom.registered_app_list_lock, flags); } - memcpy(argp, &query_req, sizeof(query_req)); + K_COPY_TO_USER(ret, argp, &query_req, sizeof(query_req)); + if(ret) { + pr_err("copy_to_user failed\n"); + ret = -EFAULT; + goto exit_free; + } ret = -EEXIST; /* app already loaded */ goto exit_free; } @@ -6439,9 +6534,13 @@ static int qseecom_create_key(struct qseecom_dev_handle *data, struct qseecom_create_key_req create_key_req; struct qseecom_key_generate_ireq generate_key_ireq; struct qseecom_key_select_ireq set_key_ireq; - uint32_t entries = 0; + int32_t entries = 0; - memcpy(&create_key_req, argp, sizeof(create_key_req)); + K_COPY_FROM_USER(ret, &create_key_req, argp, sizeof(create_key_req)); + if(ret) { + pr_err("copy_from_user failed\n"); + return ret; + } if (create_key_req.usage < QSEOS_KM_USAGE_DISK_ENCRYPTION || create_key_req.usage >= QSEOS_KM_USAGE_MAX) { pr_err("unsupported usage %d\n", create_key_req.usage); @@ -6579,9 +6678,13 @@ static int qseecom_wipe_key(struct qseecom_dev_handle *data, struct qseecom_wipe_key_req wipe_key_req; struct qseecom_key_delete_ireq delete_key_ireq; struct qseecom_key_select_ireq clear_key_ireq; - uint32_t entries = 0; + int32_t entries = 0; - memcpy(&wipe_key_req, argp, sizeof(wipe_key_req)); + K_COPY_FROM_USER(ret, &wipe_key_req, argp, sizeof(wipe_key_req)); + if(ret) { + pr_err("copy_from_user failed\n"); + return ret; + } if (wipe_key_req.usage < QSEOS_KM_USAGE_DISK_ENCRYPTION || wipe_key_req.usage >= QSEOS_KM_USAGE_MAX) { @@ -6686,7 +6789,11 @@ static int qseecom_update_key_user_info(struct qseecom_dev_handle *data, struct qseecom_update_key_userinfo_req update_key_req; struct qseecom_key_userinfo_update_ireq ireq; - memcpy(&update_key_req, argp, sizeof(update_key_req)); + K_COPY_FROM_USER(ret, &update_key_req, argp, sizeof(update_key_req)); + if(ret) { + pr_err("copy_from_user failed\n"); + return ret; + } if (update_key_req.usage < QSEOS_KM_USAGE_DISK_ENCRYPTION || update_key_req.usage >= QSEOS_KM_USAGE_MAX) { @@ -6736,7 +6843,7 @@ static int qseecom_is_es_activated(void __user *argp) { struct qseecom_is_es_activated_req req = {0}; struct qseecom_command_scm_resp resp; - int ret; + int ret = 0; if (qseecom.qsee_version < QSEE_VERSION_04) { pr_err("invalid qsee version\n"); @@ -6756,7 +6863,12 @@ static int qseecom_is_es_activated(void __user *argp) } req.is_activated = resp.result; - memcpy(argp, &req, sizeof(req)); + K_COPY_TO_USER(ret, argp, &req, sizeof(req)); + if(ret) { + pr_err("copy_to_user failed\n"); + return ret; + } + return 0; } @@ -6800,7 +6912,7 @@ static int qseecom_mdtp_cipher_dip(void __user *argp) u32 tzbuflenin, tzbuflenout; char *tzbufin = NULL, *tzbufout = NULL; struct qseecom_scm_desc desc = {0}; - int ret; + int ret = 0; phys_addr_t pain, paout; struct qtee_shm shmin = {0}, shmout = {0}; @@ -6812,7 +6924,11 @@ static int qseecom_mdtp_cipher_dip(void __user *argp) break; } - memcpy(&req, argp, sizeof(req)); + K_COPY_FROM_USER(ret, &req, argp, sizeof(req)); + if (ret) { + pr_err("copy_from_user failed, ret= %d\n", ret); + break; + } if (req.in_buf == NULL || req.out_buf == NULL || req.in_buf_size == 0 || req.in_buf_size > MAX_DIP || @@ -6832,7 +6948,12 @@ static int qseecom_mdtp_cipher_dip(void __user *argp) break; } - memcpy(tzbufin, (void __user *)req.in_buf, req.in_buf_size); + K_COPY_FROM_USER(ret, tzbufin, (void __user *)req.in_buf, req.in_buf_size); + if (ret) { + pr_err("copy_from_user failed, ret= %d\n", ret); + break; + } + qtee_shmbridge_flush_shm_buf(&shmin); /* Prepare the output buffer in kernel space */ @@ -6870,7 +6991,11 @@ static int qseecom_mdtp_cipher_dip(void __user *argp) /* Copy the output buffer from kernel space to userspace */ qtee_shmbridge_flush_shm_buf(&shmout); - memcpy((void __user *)req.out_buf, tzbufout, req.out_buf_size); + K_COPY_TO_USER(ret, (void __user *)req.out_buf, tzbufout, req.out_buf_size); + if (ret) { + pr_err("copy_to_user failed, ret=%d\n", ret); + break; + } } while (0); __qseecom_free_tzbuf(&shmin); @@ -7299,7 +7424,11 @@ static int qseecom_qteec_open_session(struct qseecom_dev_handle *data, struct qseecom_qteec_modfd_req req; int ret = 0; - memcpy(&req, argp, sizeof(struct qseecom_qteec_modfd_req)); + K_COPY_FROM_USER(ret, &req, argp, sizeof(struct qseecom_qteec_modfd_req)); + if(ret) { + pr_err("copy_from_user failed\n"); + return ret; + } ret = __qseecom_qteec_issue_cmd(data, (struct qseecom_qteec_req *)&req, QSEOS_TEE_OPEN_SESSION); @@ -7312,7 +7441,11 @@ static int qseecom_qteec_close_session(struct qseecom_dev_handle *data, struct qseecom_qteec_req req; int ret = 0; - memcpy(&req, argp, sizeof(struct qseecom_qteec_req)); + K_COPY_FROM_USER(ret, &req, argp, sizeof(struct qseecom_qteec_req)); + if(ret) { + pr_err("copy_from_user failed\n"); + return ret; + } ret = __qseecom_qteec_issue_cmd(data, &req, QSEOS_TEE_CLOSE_SESSION); return ret; } @@ -7336,7 +7469,11 @@ static int qseecom_qteec_invoke_modfd_cmd(struct qseecom_dev_handle *data, void *req_ptr = NULL; void *resp_ptr = NULL; - memcpy(&req, argp, sizeof(struct qseecom_qteec_modfd_req)); + K_COPY_FROM_USER(ret, &req, argp, sizeof(struct qseecom_qteec_modfd_req)); + if(ret) { + pr_err("copy_from_user failed\n"); + return ret; + } ret = __qseecom_qteec_validate_msg(data, (struct qseecom_qteec_req *)(&req)); if (ret) @@ -7470,7 +7607,11 @@ static int qseecom_qteec_request_cancellation(struct qseecom_dev_handle *data, struct qseecom_qteec_modfd_req req; int ret = 0; - memcpy(&req, argp, sizeof(struct qseecom_qteec_modfd_req)); + K_COPY_FROM_USER(ret, &req, argp, sizeof(struct qseecom_qteec_modfd_req)); + if(ret) { + pr_err("copy_from_user failed\n"); + return ret; + } ret = __qseecom_qteec_issue_cmd(data, (struct qseecom_qteec_req *)&req, QSEOS_TEE_REQUEST_CANCELLATION); @@ -8190,7 +8331,11 @@ long qseecom_ioctl(struct file *file, case QSEECOM_IOCTL_SET_ICE_INFO: { struct qseecom_ice_data_t ice_data; - memcpy(&ice_data, argp, sizeof(ice_data)); + K_COPY_FROM_USER(ret, &ice_data, argp, sizeof(ice_data)); + if(ret) { + pr_err("copy_from_user failed\n"); + return -EFAULT; + } qcom_ice_set_fde_flag(ice_data.flag); break; } @@ -8315,7 +8460,7 @@ static const struct file_operations qseecom_fops = { .owner = THIS_MODULE, .unlocked_ioctl = qseecom_ioctl, #ifdef CONFIG_COMPAT - .compat_ioctl = compat_qseecom_ioctl, + .compat_ioctl = qseecom_ioctl_32bit, #endif .open = qseecom_open, .release = qseecom_release @@ -8831,8 +8976,11 @@ static int qseecom_get_ce_info(struct qseecom_dev_handle *data, bool found = false; struct qseecom_ce_pipe_entry *pce_entry; - memcpy(pinfo, argp, sizeof(struct qseecom_ce_info_req)); - + K_COPY_FROM_USER(ret, pinfo, argp, sizeof(struct qseecom_ce_info_req)); + if(ret) { + pr_err("copy_from_user failed\n"); + return ret; + } switch (pinfo->usage) { case QSEOS_KM_USAGE_DISK_ENCRYPTION: case QSEOS_KM_USAGE_UFS_ICE_DISK_ENCRYPTION: @@ -8893,7 +9041,11 @@ static int qseecom_get_ce_info(struct qseecom_dev_handle *data, for (; i < MAX_CE_PIPE_PAIR_PER_UNIT; i++) pinfo->ce_pipe_entry[i].valid = 0; - memcpy(argp, pinfo, sizeof(struct qseecom_ce_info_req)); + K_COPY_TO_USER(ret, argp, pinfo, sizeof(struct qseecom_ce_info_req)); + if(ret) { + pr_err("copy_to_user failed\n"); + ret = -EFAULT; + } return ret; } @@ -8908,7 +9060,11 @@ static int qseecom_free_ce_info(struct qseecom_dev_handle *data, int i; bool found = false; - memcpy(pinfo, argp, sizeof(struct qseecom_ce_info_req)); + K_COPY_FROM_USER(ret, pinfo, argp, sizeof(struct qseecom_ce_info_req)); + if(ret) { + pr_err("copy_from_user failed\n"); + return ret; + } switch (pinfo->usage) { case QSEOS_KM_USAGE_DISK_ENCRYPTION: @@ -8963,8 +9119,11 @@ static int qseecom_query_ce_info(struct qseecom_dev_handle *data, bool found = false; struct qseecom_ce_pipe_entry *pce_entry; - memcpy(pinfo, argp, sizeof(struct qseecom_ce_info_req)); - + K_COPY_FROM_USER(ret, pinfo, argp, sizeof(struct qseecom_ce_info_req)); + if(ret) { + pr_err("copy_from_user failed\n"); + return ret; + } switch (pinfo->usage) { case QSEOS_KM_USAGE_DISK_ENCRYPTION: case QSEOS_KM_USAGE_UFS_ICE_DISK_ENCRYPTION: @@ -9022,7 +9181,11 @@ static int qseecom_query_ce_info(struct qseecom_dev_handle *data, for (; i < MAX_CE_PIPE_PAIR_PER_UNIT; i++) pinfo->ce_pipe_entry[i].valid = 0; out: - memcpy(argp, pinfo, sizeof(struct qseecom_ce_info_req)); + K_COPY_TO_USER(ret, argp, pinfo, sizeof(struct qseecom_ce_info_req)); + if(ret) { + pr_err("copy_to_user failed\n"); + ret = -EFAULT; + } return ret; } @@ -9308,6 +9471,7 @@ static int qseecom_init_control(void) qseecom.qseos_version = QSEOS_VERSION_14; qseecom.commonlib_loaded = false; qseecom.commonlib64_loaded = false; + qseecom.commonlib_loaded_by_hostvm = false; qseecom.whitelist_support = qseecom_check_whitelist_feature(); return rc; @@ -9329,6 +9493,9 @@ static int qseecom_parse_dt(struct platform_device *pdev) qseecom.commonlib64_loaded = of_property_read_bool((&pdev->dev)->of_node, "qcom,commonlib64-loaded-by-uefi"); + qseecom.commonlib_loaded_by_hostvm = + of_property_read_bool((&pdev->dev)->of_node, + "qcom,commonlib-loaded-by-hostvm"); qseecom.fde_key_size = of_property_read_bool((&pdev->dev)->of_node, "qcom,fde-key-size"); diff --git a/qseecom/qseecom_32bit_impl.c b/qseecom/qseecom_32bit_impl.c new file mode 100644 index 0000000..71d208f --- /dev/null +++ b/qseecom/qseecom_32bit_impl.c @@ -0,0 +1,943 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2014-2018, 2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include <linux/debugfs.h> +#include <linux/uaccess.h> +#include <linux/qseecom.h> +#include <linux/compat.h> +#include <linux/mman.h> +#include <linux/module.h> +#include <linux/device.h> +#include <linux/types.h> +#include <linux/platform_device.h> +#include <linux/dma-mapping.h> +#include <linux/kernel.h> +#include <linux/dmapool.h> +#include <linux/interrupt.h> +#include <linux/spinlock.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/fs.h> +#include <linux/scatterlist.h> +#include <linux/interconnect.h> +#include <linux/delay.h> +#include "qseecom_32bit_impl.h" + + +static int get_qseecom_register_listener_req_32bit( + struct qseecom_register_listener_req_32bit __user *data32, + struct qseecom_register_listener_req *data) +{ + int err; + compat_ulong_t listener_id; + compat_long_t ifd_data_fd; + compat_uptr_t virt_sb_base; + compat_ulong_t sb_size; + + err = get_user(listener_id, &data32->listener_id); + memcpy( &data->listener_id, &listener_id, sizeof(listener_id)); + err |= get_user(ifd_data_fd, &data32->ifd_data_fd); + memcpy( &data->ifd_data_fd, &ifd_data_fd, sizeof(ifd_data_fd)); + err |= get_user(virt_sb_base, &data32->virt_sb_base); + data->virt_sb_base = NULL; + memcpy(&data->virt_sb_base, &virt_sb_base, sizeof(virt_sb_base)); + err |= get_user(sb_size, &data32->sb_size); + memcpy( &data->sb_size, &sb_size, sizeof(sb_size)); + return err; +} + +static int get_qseecom_load_img_req_32bit( + struct qseecom_load_img_req_32bit __user *data32, + struct qseecom_load_img_req *data) +{ + int err; + compat_ulong_t mdt_len; + compat_ulong_t img_len; + compat_long_t ifd_data_fd; + compat_ulong_t app_arch; + compat_uint_t app_id; + char img_name; + unsigned int i; + + err = get_user(mdt_len, &data32->mdt_len); + memcpy( &data->mdt_len, &mdt_len, sizeof(mdt_len)); + err |= get_user(img_len, &data32->img_len); + memcpy( &data->img_len, &img_len, sizeof(img_len)); + err |= get_user(ifd_data_fd, &data32->ifd_data_fd); + memcpy( &data->ifd_data_fd, &ifd_data_fd, sizeof(ifd_data_fd)); + for (i = 0; i < MAX_APP_NAME_SIZE; i++) { + err |= get_user(img_name, &(data32->img_name[i])); + memcpy( &data->img_name[i], &img_name, sizeof(img_name)); + } + err |= get_user(app_arch, &data32->app_arch); + memcpy( &data->app_arch, &app_arch, sizeof(app_arch)); + err |= get_user(app_id, &data32->app_id); + memcpy( &data->app_id, &app_id, sizeof(app_id)); + return err; +} + +static int get_qseecom_send_cmd_req_32bit( + struct qseecom_send_cmd_req_32bit __user *data32, + struct qseecom_send_cmd_req *data) +{ + int err; + compat_uptr_t cmd_req_buf; + compat_uint_t cmd_req_len; + compat_uptr_t resp_buf; + compat_uint_t resp_len; + + err = get_user(cmd_req_buf, &data32->cmd_req_buf); + data->cmd_req_buf = NULL; + memcpy( &data->cmd_req_buf, &cmd_req_buf, sizeof(cmd_req_buf)); + err |= get_user(cmd_req_len, &data32->cmd_req_len); + memcpy( &data->cmd_req_len, &cmd_req_len, sizeof(cmd_req_len)); + err |= get_user(resp_buf, &data32->resp_buf); + data->resp_buf = NULL; + memcpy( &data->resp_buf, &resp_buf, sizeof(resp_buf)); + err |= get_user(resp_len, &data32->resp_len); + memcpy( &data->resp_len, &resp_len, sizeof(resp_len)); + return err; +} + +static int get_qseecom_send_modfd_cmd_req_32bit( + struct qseecom_send_modfd_cmd_req_32bit __user *data32, + struct qseecom_send_modfd_cmd_req *data) +{ + int err; + unsigned int i; + compat_uptr_t cmd_req_buf; + compat_uint_t cmd_req_len; + compat_uptr_t resp_buf; + compat_uint_t resp_len; + compat_long_t fd; + compat_ulong_t cmd_buf_offset; + + err = get_user(cmd_req_buf, &data32->cmd_req_buf); + data->cmd_req_buf = NULL; + memcpy( &data->cmd_req_buf, &cmd_req_buf, sizeof(cmd_req_buf)); + err |= get_user(cmd_req_len, &data32->cmd_req_len); + memcpy(&data->cmd_req_len, &cmd_req_len, sizeof(cmd_req_len)); + err |= get_user(resp_buf, &data32->resp_buf); + data->resp_buf = NULL; + memcpy(&data->resp_buf, &resp_buf, sizeof(resp_buf)); + err |= get_user(resp_len, &data32->resp_len); + memcpy( &data->resp_len, &resp_len, sizeof(resp_len)); + for (i = 0; i < MAX_ION_FD; i++) { + err |= get_user(fd, &data32->ifd_data[i].fd); + memcpy(&data->ifd_data[i].fd, &fd, sizeof(fd)); + err |= get_user(cmd_buf_offset, + &data32->ifd_data[i].cmd_buf_offset); + memcpy(&data->ifd_data[i].cmd_buf_offset, &cmd_buf_offset, sizeof(cmd_buf_offset)); + } + return err; +} + +static int get_qseecom_set_sb_mem_param_req_32bit( + struct qseecom_set_sb_mem_param_req_32bit __user *data32, + struct qseecom_set_sb_mem_param_req *data) +{ + int err; + compat_long_t ifd_data_fd; + compat_uptr_t virt_sb_base; + compat_ulong_t sb_len; + + err = get_user(ifd_data_fd, &data32->ifd_data_fd); + memcpy(&data->ifd_data_fd, &ifd_data_fd, sizeof(ifd_data_fd)); + err |= get_user(virt_sb_base, &data32->virt_sb_base); + data->virt_sb_base = NULL; + memcpy(&data->virt_sb_base, &virt_sb_base, sizeof(virt_sb_base)); + err |= get_user(sb_len, &data32->sb_len); + memcpy(&data->sb_len, &sb_len, sizeof(sb_len)); + return err; +} + +static int get_qseecom_qseos_version_req_32bit( + struct qseecom_qseos_version_req_32bit __user *data32, + struct qseecom_qseos_version_req *data) +{ + int err; + compat_uint_t qseos_version; + + err = get_user(qseos_version, &data32->qseos_version); + memcpy( &data->qseos_version, &qseos_version, sizeof(qseos_version)); + return err; +} + +static int get_qseecom_qseos_app_load_query_32bit( + struct qseecom_qseos_app_load_query_32bit __user *data32, + struct qseecom_qseos_app_load_query *data) +{ + int err = 0; + unsigned int i; + compat_uint_t app_id; + char app_name; + compat_ulong_t app_arch; + + for (i = 0; i < MAX_APP_NAME_SIZE; i++) { + err |= get_user(app_name, &(data32->app_name[i])); + memcpy(&data->app_name[i], &app_name, sizeof(app_name)); + } + err |= get_user(app_id, &data32->app_id); + memcpy(&data->app_id, &app_id, sizeof(app_id)); + err |= get_user(app_arch, &data32->app_arch); + memcpy(&data->app_arch, &app_arch, sizeof(app_arch)); + return err; +} + +static int get_qseecom_send_svc_cmd_req_32bit( + struct qseecom_send_svc_cmd_req_32bit __user *data32, + struct qseecom_send_svc_cmd_req *data) +{ + int err; + compat_ulong_t cmd_id; + compat_uptr_t cmd_req_buf; + compat_uint_t cmd_req_len; + compat_uptr_t resp_buf; + compat_uint_t resp_len; + + err = get_user(cmd_id, &data32->cmd_id); + memcpy(&data->cmd_id, &cmd_id, sizeof(cmd_id)); + err |= get_user(cmd_req_buf, &data32->cmd_req_buf); + data->cmd_req_buf = NULL; + memcpy(&data->cmd_req_buf, &cmd_req_buf, sizeof(cmd_req_buf)); + err |= get_user(cmd_req_len, &data32->cmd_req_len); + memcpy(&data->cmd_req_len, &cmd_req_len, sizeof(cmd_req_len)); + err |= get_user(resp_buf, &data32->resp_buf); + data->resp_buf = NULL; + memcpy(&data->resp_buf, &resp_buf, sizeof(resp_buf)); + err |= get_user(resp_len, &data32->resp_len); + memcpy(&data->resp_len, &resp_len, sizeof(resp_len)); + return err; +} + +static int get_qseecom_create_key_req_32bit( + struct qseecom_create_key_req_32bit __user *data32, + struct qseecom_create_key_req *data) +{ + int err = 0; + compat_uint_t usage; + unsigned char hash32; + unsigned int i; + + for (i = 0; i < QSEECOM_HASH_SIZE; i++) { + err |= get_user(hash32, &(data32->hash32[i])); + memcpy( &data->hash32[i], &hash32, sizeof(hash32)); + } + err = get_user(usage, &data32->usage); + memcpy(&data->usage, &usage, sizeof(usage)); + + return err; +} + +static int get_qseecom_wipe_key_req_32bit( + struct qseecom_wipe_key_req_32bit __user *data32, + struct qseecom_wipe_key_req *data) +{ + int err; + compat_uint_t usage; + compat_int_t wipe_key_flag; + + err = get_user(usage, &data32->usage); + memcpy(&data->usage, &usage, sizeof(usage)); + err |= get_user(wipe_key_flag, &data32->wipe_key_flag); + memcpy(&data->wipe_key_flag, &wipe_key_flag, sizeof(wipe_key_flag)); + + return err; +} + +static int get_qseecom_update_key_userinfo_req_32bit( + struct qseecom_update_key_userinfo_req_32bit __user *data32, + struct qseecom_update_key_userinfo_req *data) +{ + int err = 0; + compat_uint_t usage; + unsigned char current_hash32; + unsigned char new_hash32; + unsigned int i; + + for (i = 0; i < QSEECOM_HASH_SIZE; i++) { + err |= get_user(current_hash32, &(data32->current_hash32[i])); + memcpy( &data->current_hash32[i], ¤t_hash32, sizeof(current_hash32)); + } + for (i = 0; i < QSEECOM_HASH_SIZE; i++) { + err |= get_user(new_hash32, &(data32->new_hash32[i])); + memcpy( &data->new_hash32[i], &new_hash32, sizeof(new_hash32)); + } + err = get_user(usage, &data32->usage); + memcpy(&data->usage, &usage, sizeof(usage)); + + return err; +} + +static int get_qseecom_save_partition_hash_req_32bit( + struct qseecom_save_partition_hash_req_32bit __user *data32, + struct qseecom_save_partition_hash_req *data) +{ + int err; + compat_int_t partition_id; + char digest; + unsigned int i; + + err = get_user(partition_id, &data32->partition_id); + memcpy(&data->partition_id, &partition_id, sizeof(partition_id)); + for (i = 0; i < SHA256_DIGEST_LENGTH; i++) { + err |= get_user(digest, &(data32->digest[i])); + memcpy( &data->digest[i], &digest, sizeof(digest)); + } + return err; +} + +static int get_qseecom_is_es_activated_req_32bit( + struct qseecom_is_es_activated_req_32bit __user *data32, + struct qseecom_is_es_activated_req *data) +{ + compat_int_t is_activated; + int err; + + err = get_user(is_activated, &data32->is_activated); + memcpy(&data->is_activated, &is_activated, sizeof(is_activated)); + return err; +} + +static int get_qseecom_mdtp_cipher_dip_req_32bit( + struct qseecom_mdtp_cipher_dip_req_32bit __user *data32, + struct qseecom_mdtp_cipher_dip_req *data) +{ + int err; + compat_int_t in_buf_size; + compat_uptr_t in_buf; + compat_int_t out_buf_size; + compat_uptr_t out_buf; + compat_int_t direction; + + err = get_user(in_buf_size, &data32->in_buf_size); + memcpy(&data->in_buf_size, &in_buf_size, sizeof(in_buf_size)); + err |= get_user(out_buf_size, &data32->out_buf_size); + memcpy(&data->out_buf_size, &out_buf_size, sizeof(out_buf_size)); + err |= get_user(direction, &data32->direction); + memcpy(&data->direction, &direction, sizeof(direction)); + err |= get_user(in_buf, &data32->in_buf); + data->in_buf = NULL; + memcpy(&data->in_buf, &in_buf, sizeof(in_buf)); + err |= get_user(out_buf, &data32->out_buf); + data->out_buf = NULL; + memcpy(&data->out_buf, &out_buf, sizeof(out_buf)); + + return err; +} + +static int get_qseecom_send_modfd_listener_resp_32bit( + struct qseecom_send_modfd_listener_resp_32bit __user *data32, + struct qseecom_send_modfd_listener_resp *data) +{ + int err; + unsigned int i; + compat_uptr_t resp_buf_ptr; + compat_uint_t resp_len; + compat_long_t fd; + compat_ulong_t cmd_buf_offset; + + err = get_user(resp_buf_ptr, &data32->resp_buf_ptr); + data->resp_buf_ptr = NULL; + memcpy(&data->resp_buf_ptr, &resp_buf_ptr, sizeof(resp_buf_ptr)); + err |= get_user(resp_len, &data32->resp_len); + memcpy(&data->resp_len, &resp_len, sizeof(resp_len)); + for (i = 0; i < MAX_ION_FD; i++) { + err |= get_user(fd, &data32->ifd_data[i].fd); + memcpy(&data->ifd_data[i].fd, &fd, sizeof(fd)); + err |= get_user(cmd_buf_offset, + &data32->ifd_data[i].cmd_buf_offset); + memcpy(&data->ifd_data[i].cmd_buf_offset, &cmd_buf_offset, sizeof(cmd_buf_offset)); + } + return err; +} + + +static int get_qseecom_qteec_req_32bit( + struct qseecom_qteec_req_32bit __user *data32, + struct qseecom_qteec_req *data) +{ + compat_uptr_t req_ptr; + compat_ulong_t req_len; + compat_uptr_t resp_ptr; + compat_ulong_t resp_len; + int err; + + err = get_user(req_ptr, &data32->req_ptr); + data->req_ptr = NULL; + memcpy(&data->req_ptr, &req_ptr, sizeof(req_ptr)); + err |= get_user(req_len, &data32->req_len); + memcpy(&data->req_len, &req_len, sizeof(req_len)); + err |= get_user(resp_ptr, &data32->resp_ptr); + data->resp_ptr = NULL; + memcpy(&data->resp_ptr, &resp_ptr, sizeof(resp_ptr)); + err |= get_user(resp_len, &data32->resp_len); + memcpy(&data->resp_len, &resp_len, sizeof(resp_len)); + return err; +} + +static int get_qseecom_qteec_modfd_req_32bit( + struct qseecom_qteec_modfd_req_32bit __user *data32, + struct qseecom_qteec_modfd_req *data) +{ + compat_uptr_t req_ptr; + compat_ulong_t req_len; + compat_uptr_t resp_ptr; + compat_ulong_t resp_len; + compat_long_t fd; + compat_ulong_t cmd_buf_offset; + int err, i; + + err = get_user(req_ptr, &data32->req_ptr); + data->req_ptr = NULL; + memcpy(&data->req_ptr, &req_ptr, sizeof(req_ptr)); + err |= get_user(req_len, &data32->req_len); + memcpy(&data->req_len, &req_len, sizeof(req_len)); + + err |= get_user(resp_ptr, &data32->resp_ptr); + data->resp_ptr = NULL; + memcpy(&data->resp_ptr, &resp_ptr, sizeof(resp_ptr)); + err |= get_user(resp_len, &data32->resp_len); + memcpy(&data->resp_len, &resp_len, sizeof(resp_len)); + + for (i = 0; i < MAX_ION_FD; i++) { + err |= get_user(fd, &data32->ifd_data[i].fd); + memcpy(&data->ifd_data[i].fd, &fd, sizeof(fd)); + err |= get_user(cmd_buf_offset, + &data32->ifd_data[i].cmd_buf_offset); + memcpy(&data->ifd_data[i].cmd_buf_offset, &cmd_buf_offset, sizeof(cmd_buf_offset)); + } + return err; +} + +static int get_int_32bit(compat_int_t __user *data32, + int *data) +{ + compat_int_t x; + int err; + + err = get_user(x, data32); + memcpy(&data, &x, sizeof(x)); + return err; +} + +static int put_qseecom_load_img_req_32bit( + struct qseecom_load_img_req_32bit __user *data32, + struct qseecom_load_img_req *data) +{ + int err; + compat_ulong_t mdt_len; + compat_ulong_t img_len; + compat_long_t ifd_data_fd; + compat_ulong_t app_arch; + compat_int_t app_id; + char img_name; + unsigned int i; + + memcpy(&mdt_len, &data->mdt_len, sizeof(mdt_len)); + err = put_user(mdt_len, &data32->mdt_len); + memcpy(&img_len, &data->img_len, sizeof(img_len)); + err |= put_user(img_len, &data32->img_len); + memcpy(&ifd_data_fd, &data->ifd_data_fd, sizeof(ifd_data_fd)); + err |= put_user(ifd_data_fd, &data32->ifd_data_fd); + for (i = 0; i < MAX_APP_NAME_SIZE; i++) { + memcpy(&img_name, &data->img_name[i], sizeof(img_name)); + err |= put_user(img_name, &data32->img_name[i]); + } + memcpy(&app_arch, &data->app_arch, sizeof(app_arch)); + err |= put_user(app_arch, &data32->app_arch); + memcpy(&app_id, &data->app_id, sizeof(app_id)); + err |= put_user(app_id, &data32->app_id); + return err; +} + +static int put_qseecom_qseos_version_req_32bit( + struct qseecom_qseos_version_req_32bit __user *data32, + struct qseecom_qseos_version_req *data) +{ + compat_uint_t qseos_version; + int err; + memcpy(&qseos_version, &data->qseos_version, sizeof(qseos_version)); + err = put_user(qseos_version, &data32->qseos_version); + return err; +} + +static int put_qseecom_qseos_app_load_query_32bit( + struct qseecom_qseos_app_load_query_32bit __user *data32, + struct qseecom_qseos_app_load_query *data) +{ + int err = 0; + unsigned int i; + compat_int_t app_id; + compat_ulong_t app_arch; + char app_name; + + for (i = 0; i < MAX_APP_NAME_SIZE; i++) { + memcpy(&app_name, &data->app_name[i], sizeof(app_name)); + err |= put_user(app_name, &(data32->app_name[i])); + } + memcpy(&app_id, &data->app_id, sizeof(app_id)); + err |= put_user(app_id, &data32->app_id); + memcpy(&app_arch, &data->app_arch, sizeof(app_arch)); + err |= put_user(app_arch, &data32->app_arch); + + return err; +} + +static int put_qseecom_is_es_activated_req_32bit( + struct qseecom_is_es_activated_req_32bit __user *data32, + struct qseecom_is_es_activated_req *data) +{ + compat_int_t is_activated; + int err; + + memcpy(&is_activated, &data->is_activated, sizeof(is_activated)); + err = put_user(is_activated, &data32->is_activated); + return err; +} + +static unsigned int convert_cmd(unsigned int cmd) +{ + switch (cmd) { + case QSEECOM_IOCTL_REGISTER_LISTENER_REQ_32BIT: + return QSEECOM_IOCTL_REGISTER_LISTENER_REQ; + case QSEECOM_IOCTL_UNREGISTER_LISTENER_REQ_32BIT: + return QSEECOM_IOCTL_UNREGISTER_LISTENER_REQ; + case QSEECOM_IOCTL_LOAD_APP_REQ_32BIT: + return QSEECOM_IOCTL_LOAD_APP_REQ; + case QSEECOM_IOCTL_RECEIVE_REQ_32BIT: + return QSEECOM_IOCTL_RECEIVE_REQ; + case QSEECOM_IOCTL_SEND_RESP_REQ_32BIT: + return QSEECOM_IOCTL_SEND_RESP_REQ; + case QSEECOM_IOCTL_UNLOAD_APP_REQ_32BIT: + return QSEECOM_IOCTL_UNLOAD_APP_REQ; + case QSEECOM_IOCTL_PERF_ENABLE_REQ_32BIT: + return QSEECOM_IOCTL_PERF_ENABLE_REQ; + case QSEECOM_IOCTL_PERF_DISABLE_REQ_32BIT: + return QSEECOM_IOCTL_PERF_DISABLE_REQ; + case QSEECOM_IOCTL_UNLOAD_EXTERNAL_ELF_REQ_32BIT: + return QSEECOM_IOCTL_UNLOAD_EXTERNAL_ELF_REQ; + case QSEECOM_IOCTL_SET_BUS_SCALING_REQ_32BIT: + return QSEECOM_IOCTL_SET_BUS_SCALING_REQ; + case QSEECOM_IOCTL_SEND_CMD_REQ_32BIT: + return QSEECOM_IOCTL_SEND_CMD_REQ; + case QSEECOM_IOCTL_SEND_MODFD_CMD_REQ_32BIT: + return QSEECOM_IOCTL_SEND_MODFD_CMD_REQ; + case QSEECOM_IOCTL_SET_MEM_PARAM_REQ_32BIT: + return QSEECOM_IOCTL_SET_MEM_PARAM_REQ; + case QSEECOM_IOCTL_GET_QSEOS_VERSION_REQ_32BIT: + return QSEECOM_IOCTL_GET_QSEOS_VERSION_REQ; + case QSEECOM_IOCTL_LOAD_EXTERNAL_ELF_REQ_32BIT: + return QSEECOM_IOCTL_LOAD_EXTERNAL_ELF_REQ; + case QSEECOM_IOCTL_APP_LOADED_QUERY_REQ_32BIT: + return QSEECOM_IOCTL_APP_LOADED_QUERY_REQ; + case QSEECOM_IOCTL_SEND_CMD_SERVICE_REQ_32BIT: + return QSEECOM_IOCTL_SEND_CMD_SERVICE_REQ; + case QSEECOM_IOCTL_CREATE_KEY_REQ_32BIT: + return QSEECOM_IOCTL_CREATE_KEY_REQ; + case QSEECOM_IOCTL_WIPE_KEY_REQ_32BIT: + return QSEECOM_IOCTL_WIPE_KEY_REQ; + case QSEECOM_IOCTL_UPDATE_KEY_USER_INFO_REQ_32BIT: + return QSEECOM_IOCTL_UPDATE_KEY_USER_INFO_REQ; + case QSEECOM_IOCTL_SAVE_PARTITION_HASH_REQ_32BIT: + return QSEECOM_IOCTL_SAVE_PARTITION_HASH_REQ; + case QSEECOM_IOCTL_IS_ES_ACTIVATED_REQ_32BIT: + return QSEECOM_IOCTL_IS_ES_ACTIVATED_REQ; + case QSEECOM_IOCTL_SEND_MODFD_RESP_32BIT: + return QSEECOM_IOCTL_SEND_MODFD_RESP; + case QSEECOM_QTEEC_IOCTL_OPEN_SESSION_REQ_32BIT: + return QSEECOM_QTEEC_IOCTL_OPEN_SESSION_REQ; + case QSEECOM_QTEEC_IOCTL_CLOSE_SESSION_REQ_32BIT: + return QSEECOM_QTEEC_IOCTL_CLOSE_SESSION_REQ; + case QSEECOM_QTEEC_IOCTL_INVOKE_MODFD_CMD_REQ_32BIT: + return QSEECOM_QTEEC_IOCTL_INVOKE_MODFD_CMD_REQ; + case QSEECOM_QTEEC_IOCTL_REQUEST_CANCELLATION_REQ_32BIT: + return QSEECOM_QTEEC_IOCTL_REQUEST_CANCELLATION_REQ; + case QSEECOM_IOCTL_MDTP_CIPHER_DIP_REQ_32BIT: + return QSEECOM_IOCTL_MDTP_CIPHER_DIP_REQ; + case QSEECOM_IOCTL_SEND_MODFD_CMD_64_REQ_32BIT: + return QSEECOM_IOCTL_SEND_MODFD_CMD_64_REQ; + case QSEECOM_IOCTL_SEND_MODFD_RESP_64_32BIT: + return QSEECOM_IOCTL_SEND_MODFD_RESP_64; + + default: + return cmd; + } +} + +long qseecom_ioctl_32bit(struct file *file, + unsigned int cmd, unsigned long arg) +{ + long ret; + switch (cmd) { + + case QSEECOM_IOCTL_UNREGISTER_LISTENER_REQ_32BIT: + case QSEECOM_IOCTL_RECEIVE_REQ_32BIT: + case QSEECOM_IOCTL_SEND_RESP_REQ_32BIT: + case QSEECOM_IOCTL_UNLOAD_APP_REQ_32BIT: + case QSEECOM_IOCTL_PERF_ENABLE_REQ_32BIT: + case QSEECOM_IOCTL_PERF_DISABLE_REQ_32BIT: + case QSEECOM_IOCTL_UNLOAD_EXTERNAL_ELF_REQ_32BIT: { + return qseecom_ioctl(file, convert_cmd(cmd), 0); + } + break; + case QSEECOM_IOCTL_REGISTER_LISTENER_REQ_32BIT: { + struct qseecom_register_listener_req_32bit __user *data32; + struct qseecom_register_listener_req *data; + int err; + data32 = compat_ptr(arg); + data = kmalloc(sizeof(*data), GFP_KERNEL); + if (data == NULL) + return -EFAULT; + + err = get_qseecom_register_listener_req_32bit(data32, data); + if (err) + return err; + + return qseecom_ioctl(file, convert_cmd(cmd), + (unsigned long)data); + } + break; + case QSEECOM_IOCTL_LOAD_APP_REQ_32BIT: { + struct qseecom_load_img_req_32bit __user *data32; + struct qseecom_load_img_req *data; + int err; + + data32 = compat_ptr(arg); + data = kmalloc(sizeof(*data), GFP_KERNEL); + if (data == NULL) + return -EFAULT; + err = get_qseecom_load_img_req_32bit(data32, data); + if (err) + return err; + + ret = qseecom_ioctl(file, convert_cmd(cmd), + (unsigned long)data); + err = put_qseecom_load_img_req_32bit(data32, data); + return ret ? ret : err; + } + break; + case QSEECOM_IOCTL_SEND_CMD_REQ_32BIT: { + struct qseecom_send_cmd_req_32bit __user *data32; + struct qseecom_send_cmd_req *data; + int err; + + data32 = compat_ptr(arg); + data = kmalloc(sizeof(*data), GFP_KERNEL); + if (data == NULL) + return -EFAULT; + + err = get_qseecom_send_cmd_req_32bit(data32, data); + if (err) + return err; + + return qseecom_ioctl(file, convert_cmd(cmd), + (unsigned long)data); + } + break; + case QSEECOM_IOCTL_SEND_MODFD_CMD_REQ_32BIT: + case QSEECOM_IOCTL_SEND_MODFD_CMD_64_REQ_32BIT: { + struct qseecom_send_modfd_cmd_req_32bit __user *data32; + struct qseecom_send_modfd_cmd_req *data; + int err; + + data32 = compat_ptr(arg); + data = kmalloc(sizeof(*data), GFP_KERNEL); + if (data == NULL) + return -EFAULT; + + err = get_qseecom_send_modfd_cmd_req_32bit(data32, data); + if (err) + return err; + + return qseecom_ioctl(file, convert_cmd(cmd), + (unsigned long)data); + } + break; + case QSEECOM_IOCTL_SET_MEM_PARAM_REQ_32BIT: { + struct qseecom_set_sb_mem_param_req_32bit __user *data32; + struct qseecom_set_sb_mem_param_req *data; + int err; + + data32 = compat_ptr(arg); + data = kmalloc(sizeof(*data), GFP_KERNEL); + if (data == NULL) + return -EFAULT; + + err = get_qseecom_set_sb_mem_param_req_32bit(data32, data); + if (err) + return err; + + return qseecom_ioctl(file, convert_cmd(cmd), + (unsigned long)data); + } + break; + case QSEECOM_IOCTL_GET_QSEOS_VERSION_REQ_32BIT: { + struct qseecom_qseos_version_req_32bit __user *data32; + struct qseecom_qseos_version_req *data; + int err; + + data32 = compat_ptr(arg); + data = kmalloc(sizeof(*data), GFP_KERNEL); + if (data == NULL) + return -EFAULT; + + err = get_qseecom_qseos_version_req_32bit(data32, data); + if (err) + return err; + + ret = qseecom_ioctl(file, convert_cmd(cmd), + (unsigned long)data); + err = put_qseecom_qseos_version_req_32bit(data32, data); + + return ret ? ret : err; + } + break; + case QSEECOM_IOCTL_SET_BUS_SCALING_REQ_32BIT: { + compat_int_t __user *data32; + int *data; + int err; + + data32 = compat_ptr(arg); + data = kmalloc(sizeof(*data), GFP_KERNEL); + if (data == NULL) + return -EFAULT; + err = get_int_32bit(data32, data); + if (err) + return err; + return qseecom_ioctl(file, convert_cmd(cmd), + (unsigned long)data); + } + break; + case QSEECOM_IOCTL_LOAD_EXTERNAL_ELF_REQ_32BIT: { + struct qseecom_load_img_req_32bit __user *data32; + struct qseecom_load_img_req *data; + int err; + + data32 = compat_ptr(arg); + data = kmalloc(sizeof(*data), GFP_KERNEL); + if (data == NULL) + return -EFAULT; + + err = get_qseecom_load_img_req_32bit(data32, data); + if (err) + return err; + + return qseecom_ioctl(file, convert_cmd(cmd), + (unsigned long)data); + } + break; + case QSEECOM_IOCTL_APP_LOADED_QUERY_REQ_32BIT: { + struct qseecom_qseos_app_load_query_32bit __user *data32; + struct qseecom_qseos_app_load_query *data; + int err; + + data32 = compat_ptr(arg); + data = kmalloc(sizeof(*data), GFP_KERNEL); + if (data == NULL) + return -EFAULT; + + err = get_qseecom_qseos_app_load_query_32bit(data32, data); + if (err) + return err; + + ret = qseecom_ioctl(file, convert_cmd(cmd), + (unsigned long)data); + err = put_qseecom_qseos_app_load_query_32bit(data32, data); + return ret ? ret : err; + } + break; + case QSEECOM_IOCTL_SEND_CMD_SERVICE_REQ_32BIT: { + struct qseecom_send_svc_cmd_req_32bit __user *data32; + struct qseecom_send_svc_cmd_req *data; + int err; + + data32 = compat_ptr(arg); + data = kmalloc(sizeof(*data), GFP_KERNEL); + if (data == NULL) + return -EFAULT; + + err = get_qseecom_send_svc_cmd_req_32bit(data32, data); + if (err) + return err; + + return qseecom_ioctl(file, convert_cmd(cmd), + (unsigned long)data); + } + break; + case QSEECOM_IOCTL_CREATE_KEY_REQ_32BIT: { + struct qseecom_create_key_req_32bit __user *data32; + struct qseecom_create_key_req *data; + int err; + + data32 = compat_ptr(arg); + data = kmalloc(sizeof(*data), GFP_KERNEL); + if (data == NULL) + return -EFAULT; + + err = get_qseecom_create_key_req_32bit(data32, data); + if (err) + return err; + + return qseecom_ioctl(file, convert_cmd(cmd), + (unsigned long)data); + } + break; + case QSEECOM_IOCTL_WIPE_KEY_REQ_32BIT: { + struct qseecom_wipe_key_req_32bit __user *data32; + struct qseecom_wipe_key_req *data; + int err; + + data32 = compat_ptr(arg); + data = kmalloc(sizeof(*data), GFP_KERNEL); + if (data == NULL) + return -EFAULT; + + err = get_qseecom_wipe_key_req_32bit(data32, data); + if (err) + return err; + + return qseecom_ioctl(file, convert_cmd(cmd), + (unsigned long)data); + } + break; + case QSEECOM_IOCTL_UPDATE_KEY_USER_INFO_REQ_32BIT: { + struct qseecom_update_key_userinfo_req_32bit __user *data32; + struct qseecom_update_key_userinfo_req *data; + int err; + + data32 = compat_ptr(arg); + data = kmalloc(sizeof(*data), GFP_KERNEL); + if (data == NULL) + return -EFAULT; + + err = get_qseecom_update_key_userinfo_req_32bit(data32, data); + if (err) + return err; + + return qseecom_ioctl(file, convert_cmd(cmd), + (unsigned long)data); + } + break; + case QSEECOM_IOCTL_SAVE_PARTITION_HASH_REQ_32BIT: { + struct qseecom_save_partition_hash_req_32bit __user *data32; + struct qseecom_save_partition_hash_req *data; + int err; + + data32 = compat_ptr(arg); + data = kmalloc(sizeof(*data), GFP_KERNEL); + if (data == NULL) + return -EFAULT; + + err = get_qseecom_save_partition_hash_req_32bit(data32, data); + if (err) + return err; + + return qseecom_ioctl(file, convert_cmd(cmd), + (unsigned long)data); + } + break; + case QSEECOM_IOCTL_IS_ES_ACTIVATED_REQ_32BIT: { + struct qseecom_is_es_activated_req_32bit __user *data32; + struct qseecom_is_es_activated_req *data; + int err; + + data32 = compat_ptr(arg); + data = kmalloc(sizeof(*data), GFP_KERNEL); + if (data == NULL) + return -EFAULT; + + err = get_qseecom_is_es_activated_req_32bit(data32, data); + if (err) + return err; + + ret = qseecom_ioctl(file, convert_cmd(cmd), + (unsigned long)data); + err = put_qseecom_is_es_activated_req_32bit(data32, data); + return ret ? ret : err; + } + break; + case QSEECOM_IOCTL_MDTP_CIPHER_DIP_REQ_32BIT: { + struct qseecom_mdtp_cipher_dip_req_32bit __user *data32; + struct qseecom_mdtp_cipher_dip_req *data; + int err; + + data32 = compat_ptr(arg); + data = kmalloc(sizeof(*data), GFP_KERNEL); + if (data == NULL) + return -EFAULT; + + err = get_qseecom_mdtp_cipher_dip_req_32bit(data32, data); + if (err) + return err; + + return qseecom_ioctl(file, convert_cmd(cmd), + (unsigned long)data); + } + break; + case QSEECOM_IOCTL_SEND_MODFD_RESP_32BIT: + case QSEECOM_IOCTL_SEND_MODFD_RESP_64_32BIT: { + struct qseecom_send_modfd_listener_resp_32bit __user *data32; + struct qseecom_send_modfd_listener_resp *data; + int err; + + data32 = compat_ptr(arg); + data = kmalloc(sizeof(*data), GFP_KERNEL); + if (data == NULL) + return -EFAULT; + + err = get_qseecom_send_modfd_listener_resp_32bit(data32, data); + if (err) + return err; + + return qseecom_ioctl(file, convert_cmd(cmd), + (unsigned long)data); + } + break; + case QSEECOM_QTEEC_IOCTL_CLOSE_SESSION_REQ_32BIT: { + struct qseecom_qteec_req_32bit __user *data32; + struct qseecom_qteec_req *data; + int err; + + data32 = compat_ptr(arg); + data = kmalloc(sizeof(*data), GFP_KERNEL); + if (data == NULL) + return -EFAULT; + + err = get_qseecom_qteec_req_32bit(data32, data); + if (err) + return err; + + return qseecom_ioctl(file, convert_cmd(cmd), + (unsigned long)data); + } + break; + case QSEECOM_QTEEC_IOCTL_OPEN_SESSION_REQ_32BIT: + case QSEECOM_QTEEC_IOCTL_INVOKE_MODFD_CMD_REQ_32BIT: + case QSEECOM_QTEEC_IOCTL_REQUEST_CANCELLATION_REQ_32BIT: { + struct qseecom_qteec_modfd_req_32bit __user *data32; + struct qseecom_qteec_modfd_req *data; + int err; + + data32 = compat_ptr(arg); + data = kmalloc(sizeof(*data), GFP_KERNEL); + if (data == NULL) + return -EFAULT; + + err = get_qseecom_qteec_modfd_req_32bit(data32, data); + if (err) + return err; + + return qseecom_ioctl(file, convert_cmd(cmd), + (unsigned long)data); + } + break; + default: + return -ENOIOCTLCMD; + break; + } + return 0; +} diff --git a/qseecom/qseecom_32bit_impl.h b/qseecom/qseecom_32bit_impl.h new file mode 100644 index 0000000..068a49b --- /dev/null +++ b/qseecom/qseecom_32bit_impl.h @@ -0,0 +1,341 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017, 2019-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + */ +#ifndef _UAPI_COMPAT_QSEECOM_H_ +#define _UAPI_COMPAT_QSEECOM_H_ + +#include <linux/types.h> +#include <linux/ioctl.h> + +#if IS_ENABLED(CONFIG_COMPAT) +#include <linux/compat.h> + +/* + * struct qseecom_register_listener_req_32bit - + * for register listener ioctl request + * @listener_id - service id (shared between userspace and QSE) + * @ifd_data_fd - ion handle + * @virt_sb_base - shared buffer base in user space + * @sb_size - shared buffer size + */ +struct qseecom_register_listener_req_32bit { + compat_ulong_t listener_id; /* in */ + compat_long_t ifd_data_fd; /* in */ + compat_uptr_t virt_sb_base; /* in */ + compat_ulong_t sb_size; /* in */ +}; + +/* + * struct qseecom_send_cmd_req_32bit - for send command ioctl request + * @cmd_req_len - command buffer length + * @cmd_req_buf - command buffer + * @resp_len - response buffer length + * @resp_buf - response buffer + */ +struct qseecom_send_cmd_req_32bit { + compat_uptr_t cmd_req_buf; /* in */ + compat_uint_t cmd_req_len; /* in */ + compat_uptr_t resp_buf; /* in/out */ + compat_uint_t resp_len; /* in/out */ +}; + +/* + * struct qseecom_ion_fd_info_32bit - ion fd handle data information + * @fd - ion handle to some memory allocated in user space + * @cmd_buf_offset - command buffer offset + */ +struct qseecom_ion_fd_info_32bit { + compat_long_t fd; + compat_ulong_t cmd_buf_offset; +}; +/* + * struct qseecom_send_modfd_cmd_req_32bit - for send command ioctl request + * @cmd_req_len - command buffer length + * @cmd_req_buf - command buffer + * @resp_len - response buffer length + * @resp_buf - response buffer + * @ifd_data_fd - ion handle to memory allocated in user space + * @cmd_buf_offset - command buffer offset + */ +struct qseecom_send_modfd_cmd_req_32bit { + compat_uptr_t cmd_req_buf; /* in */ + compat_uint_t cmd_req_len; /* in */ + compat_uptr_t resp_buf; /* in/out */ + compat_uint_t resp_len; /* in/out */ + struct qseecom_ion_fd_info_32bit ifd_data[MAX_ION_FD]; +}; + +/* + * struct qseecom_listener_send_resp_req_32bit + * signal to continue the send_cmd req. + * Used as a trigger from HLOS service to notify QSEECOM that it's done with its + * operation and provide the response for QSEECOM can continue the incomplete + * command execution + * @resp_len - Length of the response + * @resp_buf - Response buffer where the response of the cmd should go. + */ +struct qseecom_send_resp_req_32bit { + compat_uptr_t resp_buf; /* in */ + compat_uint_t resp_len; /* in */ +}; + +/* + * struct qseecom_load_img_data_32bit + * for sending image length information and + * ion file descriptor to the qseecom driver. ion file descriptor is used + * for retrieving the ion file handle and in turn the physical address of + * the image location. + * @mdt_len - Length of the .mdt file in bytes. + * @img_len - Length of the .mdt + .b00 +..+.bxx images files in bytes + * @ion_fd - Ion file descriptor used when allocating memory. + * @img_name - Name of the image. + */ +struct qseecom_load_img_req_32bit { + compat_ulong_t mdt_len; /* in */ + compat_ulong_t img_len; /* in */ + compat_long_t ifd_data_fd; /* in */ + char img_name[MAX_APP_NAME_SIZE]; /* in */ + compat_ulong_t app_arch; /* in */ + compat_uint_t app_id; /* out*/ +}; + +struct qseecom_set_sb_mem_param_req_32bit { + compat_long_t ifd_data_fd; /* in */ + compat_uptr_t virt_sb_base; /* in */ + compat_ulong_t sb_len; /* in */ +}; + +/* + * struct qseecom_qseos_version_req_32bit - get qseos version + * @qseos_version - version number + */ +struct qseecom_qseos_version_req_32bit { + compat_uint_t qseos_version; /* in */ +}; + +/* + * struct qseecom_qseos_app_load_query_32bit - verify if app is loaded in qsee + * @app_name[MAX_APP_NAME_SIZE]- name of the app. + * @app_id - app id. + */ +struct qseecom_qseos_app_load_query_32bit { + char app_name[MAX_APP_NAME_SIZE]; /* in */ + compat_uint_t app_id; /* out */ + compat_ulong_t app_arch; +}; + +struct qseecom_send_svc_cmd_req_32bit { + compat_ulong_t cmd_id; + compat_uptr_t cmd_req_buf; /* in */ + compat_uint_t cmd_req_len; /* in */ + compat_uptr_t resp_buf; /* in/out */ + compat_uint_t resp_len; /* in/out */ +}; + +struct qseecom_create_key_req_32bit { + unsigned char hash32[QSEECOM_HASH_SIZE]; + enum qseecom_key_management_usage_type usage; +}; + +struct qseecom_wipe_key_req_32bit { + enum qseecom_key_management_usage_type usage; + compat_int_t wipe_key_flag; +}; + +struct qseecom_update_key_userinfo_req_32bit { + unsigned char current_hash32[QSEECOM_HASH_SIZE]; + unsigned char new_hash32[QSEECOM_HASH_SIZE]; + enum qseecom_key_management_usage_type usage; +}; + +/* + * struct qseecom_save_partition_hash_req_32bit + * @partition_id - partition id. + * @hash[SHA256_DIGEST_LENGTH] - sha256 digest. + */ +struct qseecom_save_partition_hash_req_32bit { + compat_int_t partition_id; /* in */ + char digest[SHA256_DIGEST_LENGTH]; /* in */ +}; + +/* + * struct qseecom_is_es_activated_req_32bit + * @is_activated - 1=true , 0=false + */ +struct qseecom_is_es_activated_req_32bit { + compat_int_t is_activated; /* out */ +}; + +/* + * struct qseecom_mdtp_cipher_dip_req_32bit + * @in_buf - input buffer + * @in_buf_size - input buffer size + * @out_buf - output buffer + * @out_buf_size - output buffer size + * @direction - 0=encrypt, 1=decrypt + */ +struct qseecom_mdtp_cipher_dip_req_32bit { + compat_uptr_t in_buf; + compat_uint_t in_buf_size; + compat_uptr_t out_buf; + compat_uint_t out_buf_size; + compat_uint_t direction; +}; + +/* + * struct qseecom_send_modfd_resp_32bit - for send command ioctl request + * @req_len - command buffer length + * @req_buf - command buffer + * @ifd_data_fd - ion handle to memory allocated in user space + * @cmd_buf_offset - command buffer offset + */ +struct qseecom_send_modfd_listener_resp_32bit { + compat_uptr_t resp_buf_ptr; /* in */ + compat_uint_t resp_len; /* in */ + struct qseecom_ion_fd_info_32bit ifd_data[MAX_ION_FD]; /* in */ +}; + +struct qseecom_qteec_req_32bit { + compat_uptr_t req_ptr; + compat_ulong_t req_len; + compat_uptr_t resp_ptr; + compat_ulong_t resp_len; +}; + +struct qseecom_qteec_modfd_req_32bit { + compat_uptr_t req_ptr; + compat_ulong_t req_len; + compat_uptr_t resp_ptr; + compat_ulong_t resp_len; + struct qseecom_ion_fd_info_32bit ifd_data[MAX_ION_FD]; +}; + +struct qseecom_ce_pipe_entry_32bit { + compat_int_t valid; + compat_uint_t ce_num; + compat_uint_t ce_pipe_pair; +}; + +struct ce_info_req_32bit { + unsigned char handle[MAX_CE_INFO_HANDLE_SIZE]; + compat_uint_t usage; + compat_uint_t unit_num; + compat_uint_t num_ce_pipe_entries; + struct qseecom_ce_pipe_entry_32bit + ce_pipe_entry[MAX_CE_PIPE_PAIR_PER_UNIT]; +}; + +struct file; +extern long qseecom_ioctl_32bit(struct file *file, + unsigned int cmd, unsigned long arg); + +extern long qseecom_ioctl(struct file *file, + unsigned int cmd, unsigned long arg); + +#define QSEECOM_IOCTL_REGISTER_LISTENER_REQ_32BIT \ + _IOWR(QSEECOM_IOC_MAGIC, 1, struct qseecom_register_listener_req_32bit) + +#define QSEECOM_IOCTL_UNREGISTER_LISTENER_REQ_32BIT \ + _IO(QSEECOM_IOC_MAGIC, 2) + +#define QSEECOM_IOCTL_SEND_CMD_REQ_32BIT \ + _IOWR(QSEECOM_IOC_MAGIC, 3, struct qseecom_send_cmd_req_32bit) + +#define QSEECOM_IOCTL_SEND_MODFD_CMD_REQ_32BIT \ + _IOWR(QSEECOM_IOC_MAGIC, 4, struct qseecom_send_modfd_cmd_req_32bit) + +#define QSEECOM_IOCTL_RECEIVE_REQ_32BIT \ + _IO(QSEECOM_IOC_MAGIC, 5) + +#define QSEECOM_IOCTL_SEND_RESP_REQ_32BIT \ + _IO(QSEECOM_IOC_MAGIC, 6) + +#define QSEECOM_IOCTL_LOAD_APP_REQ_32BIT \ + _IOWR(QSEECOM_IOC_MAGIC, 7, struct qseecom_load_img_req_32bit) + +#define QSEECOM_IOCTL_SET_MEM_PARAM_REQ_32BIT \ + _IOWR(QSEECOM_IOC_MAGIC, 8, struct qseecom_set_sb_mem_param_req_32bit) + +#define QSEECOM_IOCTL_UNLOAD_APP_REQ_32BIT \ + _IO(QSEECOM_IOC_MAGIC, 9) + +#define QSEECOM_IOCTL_GET_QSEOS_VERSION_REQ_32BIT \ + _IOWR(QSEECOM_IOC_MAGIC, 10, struct qseecom_qseos_version_req_32bit) + +#define QSEECOM_IOCTL_PERF_ENABLE_REQ_32BIT \ + _IO(QSEECOM_IOC_MAGIC, 11) + +#define QSEECOM_IOCTL_PERF_DISABLE_REQ_32BIT \ + _IO(QSEECOM_IOC_MAGIC, 12) + +#define QSEECOM_IOCTL_LOAD_EXTERNAL_ELF_REQ_32BIT \ + _IOWR(QSEECOM_IOC_MAGIC, 13, struct qseecom_load_img_req_32bit) + +#define QSEECOM_IOCTL_UNLOAD_EXTERNAL_ELF_REQ_32BIT \ + _IO(QSEECOM_IOC_MAGIC, 14) + +#define QSEECOM_IOCTL_APP_LOADED_QUERY_REQ_32BIT \ + _IOWR(QSEECOM_IOC_MAGIC, 15, struct qseecom_qseos_app_load_query_32bit) + +#define QSEECOM_IOCTL_SEND_CMD_SERVICE_REQ_32BIT \ + _IOWR(QSEECOM_IOC_MAGIC, 16, struct qseecom_send_svc_cmd_req_32bit) + +#define QSEECOM_IOCTL_CREATE_KEY_REQ_32BIT \ + _IOWR(QSEECOM_IOC_MAGIC, 17, struct qseecom_create_key_req_32bit) + +#define QSEECOM_IOCTL_WIPE_KEY_REQ_32BIT \ + _IOWR(QSEECOM_IOC_MAGIC, 18, struct qseecom_wipe_key_req_32bit) + +#define QSEECOM_IOCTL_SAVE_PARTITION_HASH_REQ_32BIT \ + _IOWR(QSEECOM_IOC_MAGIC, 19, \ + struct qseecom_save_partition_hash_req_32bit) + +#define QSEECOM_IOCTL_IS_ES_ACTIVATED_REQ_32BIT \ + _IOWR(QSEECOM_IOC_MAGIC, 20, struct qseecom_is_es_activated_req_32bit) + +#define QSEECOM_IOCTL_SEND_MODFD_RESP_32BIT \ + _IOWR(QSEECOM_IOC_MAGIC, 21, \ + struct qseecom_send_modfd_listener_resp_32bit) + +#define QSEECOM_IOCTL_SET_BUS_SCALING_REQ_32BIT \ + _IOWR(QSEECOM_IOC_MAGIC, 23, int) + +#define QSEECOM_IOCTL_UPDATE_KEY_USER_INFO_REQ_32BIT \ + _IOWR(QSEECOM_IOC_MAGIC, 24, \ + struct qseecom_update_key_userinfo_req_32bit) + +#define QSEECOM_QTEEC_IOCTL_OPEN_SESSION_REQ_32BIT \ + _IOWR(QSEECOM_IOC_MAGIC, 30, struct qseecom_qteec_modfd_req_32bit) + +#define QSEECOM_QTEEC_IOCTL_CLOSE_SESSION_REQ_32BIT \ + _IOWR(QSEECOM_IOC_MAGIC, 31, struct qseecom_qteec_req_32bit) + +#define QSEECOM_QTEEC_IOCTL_INVOKE_MODFD_CMD_REQ_32BIT \ + _IOWR(QSEECOM_IOC_MAGIC, 32, struct qseecom_qteec_modfd_req_32bit) + +#define QSEECOM_QTEEC_IOCTL_REQUEST_CANCELLATION_REQ_32BIT \ + _IOWR(QSEECOM_IOC_MAGIC, 33, struct qseecom_qteec_modfd_req_32bit) + +#define QSEECOM_IOCTL_MDTP_CIPHER_DIP_REQ_32BIT \ + _IOWR(QSEECOM_IOC_MAGIC, 34, struct qseecom_mdtp_cipher_dip_req_32bit) + +#define QSEECOM_IOCTL_SEND_MODFD_CMD_64_REQ_32BIT \ + _IOWR(QSEECOM_IOC_MAGIC, 35, struct qseecom_send_modfd_cmd_req_32bit) + +#define QSEECOM_IOCTL_SEND_MODFD_RESP_64_32BIT \ + _IOWR(QSEECOM_IOC_MAGIC, 36, \ + struct qseecom_send_modfd_listener_resp_32bit) +#define QSEECOM_IOCTL_GET_CE_PIPE_INFO_32BIT \ + _IOWR(QSEECOM_IOC_MAGIC, 40, \ + struct qseecom_ce_info_req) +#define QSEECOM_IOCTL_FREE_CE_PIPE_INFO_32BIT \ + _IOWR(QSEECOM_IOC_MAGIC, 41, \ + struct qseecom_ce_info_req) +#define QSEECOM_IOCTL_QUERY_CE_PIPE_INFO_32BIT \ + _IOWR(QSEECOM_IOC_MAGIC, 42, \ + struct qseecom_ce_info_req_32bit) + +#endif +#endif /* _UAPI_COMPAT_QSEECOM_H_ */ diff --git a/securemsm_kernel_vendor_board.mk b/securemsm_kernel_vendor_board.mk index 5638d94..eade938 100644 --- a/securemsm_kernel_vendor_board.mk +++ b/securemsm_kernel_vendor_board.mk @@ -25,6 +25,9 @@ BOARD_VENDOR_KERNEL_MODULES += $(KERNEL_MODULES_OUT)/tz_log_dlkm.ko \ BOARD_VENDOR_RAMDISK_KERNEL_MODULES += $(KERNEL_MODULES_OUT)/tz_log_dlkm.ko \ $(KERNEL_MODULES_OUT)/hdcp_qseecom_dlkm.ko \ + $(KERNEL_MODULES_OUT)/qrng_dlkm.ko \ + +BOARD_VENDOR_RAMDISK_KERNEL_MODULES_LOAD += $(KERNEL_MODULES_OUT)/qrng_dlkm.ko BOARD_VENDOR_RAMDISK_RECOVERY_KERNEL_MODULES_LOAD += $(KERNEL_MODULES_OUT)/hdcp_qseecom_dlkm.ko @@ -37,5 +40,6 @@ ifneq (, $(filter true, $(TARGET_ENABLE_QSEECOM) $(TARGET_BOARD_AUTO))) BOARD_VENDOR_KERNEL_MODULES += $(KERNEL_MODULES_OUT)/qseecom_dlkm.ko BOARD_VENDOR_RAMDISK_KERNEL_MODULES += $(KERNEL_MODULES_OUT)/qseecom_dlkm.ko BOARD_VENDOR_RAMDISK_RECOVERY_KERNEL_MODULES_LOAD += $(KERNEL_MODULES_OUT)/qseecom_dlkm.ko +BOARD_VENDOR_RAMDISK_KERNEL_MODULES_LOAD += $(KERNEL_MODULES_OUT)/qseecom_dlkm.ko endif #TARGET_ENABLE_QSEECOM OR TARGET_BOARD_AUTO endif #ENABLE_SECUREMSM_DLKM diff --git a/smcinvoke/IClientEnv.h b/smcinvoke/IClientEnv.h index 2c6d329..b974985 100644 --- a/smcinvoke/IClientEnv.h +++ b/smcinvoke/IClientEnv.h @@ -10,6 +10,8 @@ #define IClientEnv_OP_registerWithWhitelist 3 #define IClientEnv_OP_notifyDomainChange 4 #define IClientEnv_OP_registerWithCredentials 5 +#define IClientEnv_OP_accept 6 +#define IClientEnv_OP_adciShutdown 7 static inline int32_t IClientEnv_release(struct Object self) @@ -115,3 +117,14 @@ IClientEnv_registerWithCredentials(struct Object self, struct Object return result; } +static inline int32_t +IClientEnv_accept(struct Object self) +{ + return Object_invoke(self, IClientEnv_OP_accept, 0, 0); +} + +static inline int32_t +IClientEnv_adciShutdown(struct Object self) +{ + return Object_invoke(self, IClientEnv_OP_adciShutdown, 0, 0); +} diff --git a/smcinvoke/smcinvoke.c b/smcinvoke/smcinvoke.c index 3932708..f230b8e 100644 --- a/smcinvoke/smcinvoke.c +++ b/smcinvoke/smcinvoke.c @@ -164,6 +164,7 @@ static DEFINE_MUTEX(g_smcinvoke_lock); enum worker_thread_type { SHMB_WORKER_THREAD = 0, OBJECT_WORKER_THREAD, + ADCI_WORKER_THREAD, MAX_THREAD_NUMBER }; @@ -321,7 +322,8 @@ struct smcinvoke_worker_thread { static struct smcinvoke_worker_thread smcinvoke[MAX_THREAD_NUMBER]; static const char thread_name[MAX_THREAD_NUMBER][MAX_CHAR_NAME] = { - "smcinvoke_shmbridge_postprocess", "smcinvoke_object_postprocess"}; + "smcinvoke_shmbridge_postprocess", "smcinvoke_object_postprocess", "smcinvoke_adci_thread"}; +static struct Object adci_clientEnv = Object_NULL; static int prepare_send_scm_msg(const uint8_t *in_buf, phys_addr_t in_paddr, size_t in_buf_len, @@ -557,6 +559,38 @@ out: return ret; } +static void smcinvoke_start_adci_thread(void) +{ + + int32_t ret = OBJECT_ERROR; + int retry_count = 0; + + ret = get_client_env_object(&adci_clientEnv); + if (ret) { + pr_err("failed to get clientEnv for ADCI invoke thread. ret = %d\n", ret); + adci_clientEnv = Object_NULL; + goto out; + } + /* Invoke call to QTEE which should never return if ADCI is supported */ + do { + ret = IClientEnv_accept(adci_clientEnv); + if (ret == OBJECT_ERROR_BUSY) { + pr_err("Secure side is busy,will retry after 5 ms, retry_count = %d",retry_count); + msleep(5); + } + } while ((ret == OBJECT_ERROR_BUSY) && (retry_count++ < SMCINVOKE_INTERFACE_MAX_RETRY)); + + if (ret == OBJECT_ERROR_INVALID) + pr_err("ADCI feature is not supported on this chipsets, ret = %d\n", ret); + /* Need to take decesion here if we want to restart the ADCI thread */ + else + pr_err("Received response from QTEE, ret = %d\n", ret); +out: + /* Control should reach to this point only if ADCI feature is not supported by QTEE + (or) ADCI thread held in QTEE is released. */ + Object_ASSIGN_NULL(adci_clientEnv); +} + static void __wakeup_postprocess_kthread(struct smcinvoke_worker_thread *smcinvoke) { if (smcinvoke) { @@ -579,29 +613,45 @@ static int smcinvoke_postprocess_kthread_func(void *data) return -EINVAL; } - tag = smcinvoke_wrk_trd->type == SHMB_WORKER_THREAD ? "shmbridge":"object"; - while (!kthread_should_stop()) { wait_event_interruptible( smcinvoke_wrk_trd->postprocess_kthread_wq, kthread_should_stop() || (atomic_read(&smcinvoke_wrk_trd->postprocess_kthread_state) == POST_KT_WAKEUP)); - pr_debug("kthread to %s postprocess is called %d\n", - tag, - atomic_read(&smcinvoke_wrk_trd->postprocess_kthread_state)); switch (smcinvoke_wrk_trd->type) { case SHMB_WORKER_THREAD: + tag = "shmbridge"; + pr_debug("kthread to %s postprocess is called %d\n", + tag, atomic_read(&smcinvoke_wrk_trd->postprocess_kthread_state)); smcinvoke_shmbridge_post_process(); break; case OBJECT_WORKER_THREAD: + tag = "object"; + pr_debug("kthread to %s postprocess is called %d\n", + tag, atomic_read(&smcinvoke_wrk_trd->postprocess_kthread_state)); smcinvoke_object_post_process(); break; + case ADCI_WORKER_THREAD: + tag = "adci"; + pr_debug("kthread to %s postprocess is called %d\n", + tag, atomic_read(&smcinvoke_wrk_trd->postprocess_kthread_state)); + smcinvoke_start_adci_thread(); + break; default: pr_err("Invalid thread type(%d), do nothing.\n", (int)smcinvoke_wrk_trd->type); break; } + /* For ADCI thread, if control reaches here, that indicates either ADCI + * thread is not supported (or) released by QTEE. Since ADCI thread is + * getting signaled only during the smcinvoke driver initialization, + * there is no point of putting the thread into sleep state again. All the + * required post-processing will be taken care by object and shmbridge threads. + */ + if(smcinvoke_wrk_trd->type == ADCI_WORKER_THREAD) { + break; + } atomic_set(&smcinvoke_wrk_trd->postprocess_kthread_state, POST_KT_SLEEP); } @@ -615,7 +665,7 @@ static int smcinvoke_create_kthreads(void) { int i, rc = 0; const enum worker_thread_type thread_type[MAX_THREAD_NUMBER] = { - SHMB_WORKER_THREAD, OBJECT_WORKER_THREAD}; + SHMB_WORKER_THREAD, OBJECT_WORKER_THREAD, ADCI_WORKER_THREAD}; for (i = 0; i < MAX_THREAD_NUMBER; i++) { init_waitqueue_head(&smcinvoke[i].postprocess_kthread_wq); @@ -639,9 +689,26 @@ static int smcinvoke_create_kthreads(void) static void smcinvoke_destroy_kthreads(void) { int i; + int32_t ret = OBJECT_ERROR; + int retry_count = 0; + + if(!Object_isNull(adci_clientEnv)) { + do { + ret = IClientEnv_adciShutdown(adci_clientEnv); + if (ret == OBJECT_ERROR_BUSY) { + pr_err("Secure side is busy,will retry after 5 ms, retry_count = %d",retry_count); + msleep(5); + } + } while ((ret == OBJECT_ERROR_BUSY) && (retry_count++ < SMCINVOKE_INTERFACE_MAX_RETRY)); + if(OBJECT_isERROR(ret)) { + pr_err("adciShutdown in QTEE failed with error = %d\n", ret); + } + Object_ASSIGN_NULL(adci_clientEnv); + } - for (i = 0; i < MAX_THREAD_NUMBER; i++) + for (i = 0; i < MAX_THREAD_NUMBER; i++) { kthread_stop(smcinvoke[i].postprocess_kthread_task); + } } static inline void free_mem_obj_locked(struct smcinvoke_mem_obj *mem_obj) @@ -1348,7 +1415,7 @@ static int invoke_cmd_handler(int cmd, phys_addr_t in_paddr, size_t in_buf_len, case SMCINVOKE_CB_RSP_CMD: if (legacy_smc_call) - qtee_shmbridge_inv_shm_buf(out_shm); + qtee_shmbridge_flush_shm_buf(out_shm); ret = qcom_scm_invoke_callback_response(virt_to_phys(out_buf), out_buf_len, result, response_type, data); if (legacy_smc_call) { @@ -2282,7 +2349,9 @@ static long process_invoke_req(struct file *filp, unsigned int cmd, if (context_type == SMCINVOKE_OBJ_TYPE_TZ_OBJ && tzobj->tzhandle == SMCINVOKE_TZ_ROOT_OBJ && (req.op == IClientEnv_OP_notifyDomainChange || - req.op == IClientEnv_OP_registerWithCredentials)) { + req.op == IClientEnv_OP_registerWithCredentials || + req.op == IClientEnv_OP_accept || + req.op == IClientEnv_OP_adciShutdown)) { pr_err("invalid rootenv op\n"); return -EINVAL; } @@ -2747,6 +2816,7 @@ static int smcinvoke_probe(struct platform_device *pdev) pr_err("failed to get qseecom kernel func ops %d", rc); } #endif + __wakeup_postprocess_kthread(&smcinvoke[ADCI_WORKER_THREAD]); return 0; exit_destroy_device: diff --git a/smcinvoke/smcinvoke_kernel.c b/smcinvoke/smcinvoke_kernel.c index 200d327..320da7c 100644 --- a/smcinvoke/smcinvoke_kernel.c +++ b/smcinvoke/smcinvoke_kernel.c @@ -7,6 +7,7 @@ #include <linux/fs.h> #include <linux/fdtable.h> #include <linux/anon_inodes.h> +#include <linux/delay.h> #include <linux/kref.h> #include <linux/types.h> #include <linux/slab.h> @@ -295,6 +296,7 @@ static int get_root_obj(struct Object *rootObj) int32_t get_client_env_object(struct Object *clientEnvObj) { int32_t ret = OBJECT_ERROR; + int retry_count = 0; struct Object rootObj = Object_NULL; /* get rootObj */ @@ -305,8 +307,15 @@ int32_t get_client_env_object(struct Object *clientEnvObj) } /* get client env */ - ret = IClientEnv_registerWithCredentials(rootObj, + do { + ret = IClientEnv_registerWithCredentials(rootObj, Object_NULL, clientEnvObj); + if (ret == OBJECT_ERROR_BUSY) { + pr_err("Secure side is busy,will retry after 5 ms, retry_count = %d",retry_count); + msleep(5); + } + } while ((ret == OBJECT_ERROR_BUSY) && (retry_count++ < SMCINVOKE_INTERFACE_MAX_RETRY)); + if (ret) pr_err("Failed to get ClientEnvObject, ret = %d\n", ret); Object_release(rootObj); diff --git a/smcinvoke/smcinvoke_object.h b/smcinvoke/smcinvoke_object.h index 27c66da..f3c2aa5 100644 --- a/smcinvoke/smcinvoke_object.h +++ b/smcinvoke/smcinvoke_object.h @@ -184,6 +184,7 @@ static inline void Object_replace(struct Object *loc, struct Object objNew) } #define Object_ASSIGN_NULL(loc) Object_replace(&(loc), Object_NULL) +#define SMCINVOKE_INTERFACE_MAX_RETRY 5 int smcinvoke_release_from_kernel_client(int fd); |