From 674704aa211dbd7932d533a656bf43144c5db6fe Mon Sep 17 00:00:00 2001 From: Zhen Kong Date: Wed, 29 Apr 2020 12:00:53 -0700 Subject: [PATCH] firmware: qcom: add enlarged qsee log support make changes to support enlarged qsee logs support. Change-Id: I15908f7d2bee2dce0b35db751340a71f340ffeea Signed-off-by: Zhen Kong --- drivers/firmware/qcom/tz_log.c | 244 +++++++++++++++++++++++++++------ drivers/firmware/qcom_scm.c | 7 + include/linux/qcom_scm.h | 3 + 3 files changed, 215 insertions(+), 39 deletions(-) diff --git a/drivers/firmware/qcom/tz_log.c b/drivers/firmware/qcom/tz_log.c index 102e7969d7eb..5fbf594c0fc7 100644 --- a/drivers/firmware/qcom/tz_log.c +++ b/drivers/firmware/qcom/tz_log.c @@ -23,11 +23,22 @@ /* QSEE_LOG_BUF_SIZE = 32K */ #define QSEE_LOG_BUF_SIZE 0x8000 -/* MAX_ENCR_LOG_BUFF_SIZE = 36K (include header, and page align) */ -#define MAX_ENCR_LOG_BUFF_SIZE (QSEE_LOG_BUF_SIZE + PAGE_SIZE) +/* enlarged qsee log buf size is 128K by default */ +#define QSEE_LOG_BUF_SIZE_V2 0x20000 /* TZ Diagnostic Area legacy version number */ #define TZBSP_DIAG_MAJOR_VERSION_LEGACY 2 + +/* TZ Diagnostic Area version number */ +#define TZBSP_FVER_MAJOR_MINOR_MASK 0x3FF /* 10 bits */ +#define TZBSP_FVER_MAJOR_SHIFT 22 +#define TZBSP_FVER_MINOR_SHIFT 12 +#define TZBSP_DIAG_MAJOR_VERSION_V9 9 +#define TZBSP_DIAG_MINOR_VERSION_V2 2 + +/* TZ Diag Feature Version Id */ +#define QCOM_SCM_FEAT_DIAG_ID 0x06 + /* * Preprocessor Definitions and Constants */ @@ -160,6 +171,11 @@ struct tzdbg_log_pos_t { uint16_t offset; }; +struct tzdbg_log_pos_v2_t { + uint32_t wrap; + uint32_t offset; +}; + /* * Log ring buffer */ @@ -169,6 +185,12 @@ struct tzdbg_log_t { uint8_t log_buf[]; }; +struct tzdbg_log_v2_t { + struct tzdbg_log_pos_v2_t log_pos; + /* open ended array to the end of the 4K IMEM buffer */ + uint8_t log_buf[]; +}; + /* * Diagnostic Table * Note: This is the reference data structure for tz diagnostic table @@ -309,6 +331,7 @@ struct tzdbg { bool is_hyplog_enabled; uint32_t tz_version; bool is_encrypted_log_enabled; + bool is_enlarged_buf; }; struct tzbsp_encr_log_t { @@ -350,9 +373,11 @@ static struct tzdbg tzdbg = { }; static struct tzdbg_log_t *g_qsee_log; +static struct tzdbg_log_v2_t *g_qsee_log_v2; static dma_addr_t coh_pmem; static uint32_t debug_rw_buf_size; static uint32_t display_buf_size; +static uint32_t qseelog_buf_size; static phys_addr_t disp_buf_paddr; static uint64_t qseelog_shmbridge_handle; @@ -634,6 +659,83 @@ static int _disp_log_stats(struct tzdbg_log_t *log, log_start->offset = (log->log_pos.offset + 1) % log_len; } + pr_debug("diag_buf wrap = %u, offset = %u\n", + log->log_pos.wrap, log->log_pos.offset); + while (log_start->offset == log->log_pos.offset) { + /* + * No data in ring buffer, + * so we'll hang around until something happens + */ + unsigned long t = msleep_interruptible(50); + + if (t != 0) { + /* Some event woke us up, so let's quit */ + return 0; +} + + if (buf_idx == TZDBG_LOG) + memcpy_fromio((void *)tzdbg.diag_buf, tzdbg.virt_iobase, + debug_rw_buf_size); + + } + + max_len = (count > debug_rw_buf_size) ? debug_rw_buf_size : count; + + pr_debug("diag_buf wrap = %u, offset = %u\n", + log->log_pos.wrap, log->log_pos.offset); + /* + * Read from ring buff while there is data and space in return buff + */ + while ((log_start->offset != log->log_pos.offset) && (len < max_len)) { + tzdbg.disp_buf[i++] = log->log_buf[log_start->offset]; + log_start->offset = (log_start->offset + 1) % log_len; + if (log_start->offset == 0) + ++log_start->wrap; + ++len; + } + + /* + * return buffer to caller + */ + tzdbg.stat[buf_idx].data = tzdbg.disp_buf; + return len; +} + +static int _disp_log_stats_v2(struct tzdbg_log_v2_t *log, + struct tzdbg_log_pos_v2_t *log_start, uint32_t log_len, + size_t count, uint32_t buf_idx) +{ + uint32_t wrap_start; + uint32_t wrap_end; + uint32_t wrap_cnt; + int max_len; + int len = 0; + int i = 0; + + wrap_start = log_start->wrap; + wrap_end = log->log_pos.wrap; + + /* Calculate difference in # of buffer wrap-arounds */ + if (wrap_end >= wrap_start) + wrap_cnt = wrap_end - wrap_start; + else { + /* wrap counter has wrapped around, invalidate start position */ + wrap_cnt = 2; +} + + if (wrap_cnt > 1) { + /* end position has wrapped around more than once, */ + /* current start no longer valid */ + log_start->wrap = log->log_pos.wrap - 1; + log_start->offset = (log->log_pos.offset + 1) % log_len; + } else if ((wrap_cnt == 1) && + (log->log_pos.offset > log_start->offset)) { + /* end position has overwritten start */ + log_start->offset = (log->log_pos.offset + 1) % log_len; + } + pr_debug("diag_buf wrap = %u, offset = %u\n", + log->log_pos.wrap, log->log_pos.offset); + while (log_start->offset == log->log_pos.offset) { /* * No data in ring buffer, @@ -654,6 +756,9 @@ static int _disp_log_stats(struct tzdbg_log_t *log, max_len = (count > debug_rw_buf_size) ? debug_rw_buf_size : count; + pr_debug("diag_buf wrap = %u, offset = %u\n", + log->log_pos.wrap, log->log_pos.offset); + /* * Read from ring buff while there is data and space in return buff */ @@ -827,15 +932,28 @@ static int _disp_encrpted_log_stats(struct encrypted_log_info *enc_log_info, static int _disp_tz_log_stats(size_t count) { - static struct tzdbg_log_pos_t log_start = {0}; - struct tzdbg_log_t *log_ptr; + if (!tzdbg.is_enlarged_buf) { + static struct tzdbg_log_pos_t log_start = {0}; + struct tzdbg_log_t *log_ptr; - log_ptr = (struct tzdbg_log_t *)((unsigned char *)tzdbg.diag_buf + + log_ptr = (struct tzdbg_log_t *)( + (unsigned char *)tzdbg.diag_buf + tzdbg.diag_buf->ring_off - offsetof(struct tzdbg_log_t, log_buf)); - return _disp_log_stats(log_ptr, &log_start, + return _disp_log_stats(log_ptr, &log_start, tzdbg.diag_buf->ring_len, count, TZDBG_LOG); + } else { + static struct tzdbg_log_pos_v2_t log_start_v2 = {0}; + struct tzdbg_log_v2_t *log_v2_ptr; + + log_v2_ptr = (struct tzdbg_log_v2_t *)( + (unsigned char *)tzdbg.diag_buf + + tzdbg.diag_buf->ring_off - + offsetof(struct tzdbg_log_v2_t, log_buf)); + return _disp_log_stats_v2(log_v2_ptr, &log_start_v2, + tzdbg.diag_buf->ring_len, count, TZDBG_LOG); + } } static int _disp_hyp_log_stats(size_t count) @@ -852,11 +970,19 @@ static int _disp_hyp_log_stats(size_t count) static int _disp_qsee_log_stats(size_t count) { - static struct tzdbg_log_pos_t log_start = {0}; + if (!tzdbg.is_enlarged_buf) { + static struct tzdbg_log_pos_t log_start = {0}; - return _disp_log_stats(g_qsee_log, &log_start, + return _disp_log_stats(g_qsee_log, &log_start, QSEE_LOG_BUF_SIZE - sizeof(struct tzdbg_log_pos_t), count, TZDBG_QSEE_LOG); + } else { + static struct tzdbg_log_pos_v2_t log_start_v2 = {0}; + + return _disp_log_stats_v2(g_qsee_log_v2, &log_start_v2, + QSEE_LOG_BUF_SIZE - sizeof(struct tzdbg_log_pos_v2_t), + count, TZDBG_QSEE_LOG); + } } static int _disp_hyp_general_stats(size_t count) @@ -903,7 +1029,8 @@ static ssize_t tzdbgfs_read_unencrypted(struct file *file, char __user *buf, if (tz_id == TZDBG_BOOT || tz_id == TZDBG_RESET || tz_id == TZDBG_INTERRUPT || tz_id == TZDBG_GENERAL || - tz_id == TZDBG_VMID || tz_id == TZDBG_LOG) + tz_id == TZDBG_VMID || tz_id == TZDBG_LOG || + tz_id == TZDBG_QSEE_LOG) memcpy_fromio((void *)tzdbg.diag_buf, tzdbg.virt_iobase, debug_rw_buf_size); @@ -966,7 +1093,7 @@ static ssize_t tzdbgfs_read_encrypted(struct file *file, char __user *buf, int tz_id = *(int *)(file->private_data); struct tzdbg_stat *stat = &(tzdbg.stat[tz_id]); - pr_debug("tz_id = %d\n", tz_id); + pr_debug("%s: tz_id = %d\n", __func__, tz_id); if (tz_id >= TZDBG_STATS_MAX) { pr_err("invalid encrypted log id %d\n", tz_id); @@ -1023,20 +1150,31 @@ static const struct file_operations tzdbg_fops = { */ static int tzdbg_register_qsee_log_buf(struct platform_device *pdev) { - size_t len = QSEE_LOG_BUF_SIZE; int ret = 0; void *buf = NULL; uint32_t ns_vmids[] = {VMID_HLOS}; uint32_t ns_vm_perms[] = {PERM_READ | PERM_WRITE}; uint32_t ns_vm_nums = 1; - buf = dma_alloc_coherent(&pdev->dev, len, &coh_pmem, GFP_KERNEL); + if (tzdbg.is_enlarged_buf) { + if (of_property_read_u32((&pdev->dev)->of_node, + "qseelog-buf-size-v2", &qseelog_buf_size)) { + pr_debug("Enlarged qseelog buf size isn't defined\n"); + qseelog_buf_size = QSEE_LOG_BUF_SIZE_V2; + } + } else { + qseelog_buf_size = QSEE_LOG_BUF_SIZE; + } + pr_debug("qseelog buf size is 0x%x\n", qseelog_buf_size); + + buf = dma_alloc_coherent(&pdev->dev, + qseelog_buf_size, &coh_pmem, GFP_KERNEL); if (buf == NULL) return -ENOMEM; if (!tzdbg.is_encrypted_log_enabled) { ret = qtee_shmbridge_register(coh_pmem, - len, ns_vmids, ns_vm_perms, ns_vm_nums, + qseelog_buf_size, ns_vmids, ns_vm_perms, ns_vm_nums, PERM_READ | PERM_WRITE, &qseelog_shmbridge_handle); if (ret) { @@ -1048,7 +1186,10 @@ static int tzdbg_register_qsee_log_buf(struct platform_device *pdev) g_qsee_log = (struct tzdbg_log_t *)buf; g_qsee_log->log_pos.wrap = g_qsee_log->log_pos.offset = 0; - ret = qcom_scm_register_qsee_log_buf(coh_pmem, len); + g_qsee_log_v2 = (struct tzdbg_log_v2_t *)buf; + g_qsee_log_v2->log_pos.wrap = g_qsee_log_v2->log_pos.offset = 0; + + ret = qcom_scm_register_qsee_log_buf(coh_pmem, qseelog_buf_size); if (ret != QSEOS_RESULT_SUCCESS) { pr_err( "%s: scm_call to register log buf failed, resp result =%lld\n", @@ -1062,17 +1203,17 @@ exit_dereg_bridge: if (!tzdbg.is_encrypted_log_enabled) qtee_shmbridge_deregister(qseelog_shmbridge_handle); exit_free_mem: - dma_free_coherent(&pdev->dev, len, (void *)g_qsee_log, coh_pmem); + dma_free_coherent(&pdev->dev, qseelog_buf_size, + (void *)g_qsee_log, coh_pmem); return ret; } static void tzdbg_free_qsee_log_buf(struct platform_device *pdev) { - size_t len = QSEE_LOG_BUF_SIZE; - if (!tzdbg.is_encrypted_log_enabled) qtee_shmbridge_deregister(qseelog_shmbridge_handle); - dma_free_coherent(&pdev->dev, len, (void *)g_qsee_log, coh_pmem); + dma_free_coherent(&pdev->dev, qseelog_buf_size, + (void *)g_qsee_log, coh_pmem); } static int tzdbg_allocate_encrypted_log_buf(struct platform_device *pdev) @@ -1085,7 +1226,8 @@ static int tzdbg_allocate_encrypted_log_buf(struct platform_device *pdev) if (!tzdbg.is_encrypted_log_enabled) return 0; - enc_qseelog_info.size = MAX_ENCR_LOG_BUFF_SIZE; + /* max encrypted qsee log buf zize (include header, and page align) */ + enc_qseelog_info.size = qseelog_buf_size + PAGE_SIZE; enc_qseelog_info.vaddr = dma_alloc_coherent(&pdev->dev, enc_qseelog_info.size, @@ -1119,7 +1261,7 @@ static int tzdbg_allocate_encrypted_log_buf(struct platform_device *pdev) goto exit_free_tzlog; } pr_debug("Alloc memory for encr_tz_log, size %zu\n", - enc_qseelog_info.size); + enc_qseelog_info.size); return 0; @@ -1233,18 +1375,36 @@ static int __update_hypdbg_base(struct platform_device *pdev, return 0; } -static void tzdbg_get_tz_version(void) +static int tzdbg_get_tz_version(void) { u64 version; int ret = 0; ret = qcom_scm_get_tz_log_feat_id(&version); - if (ret) + if (ret) { pr_err("%s: scm_call to get tz version failed\n", __func__); + return ret; + } + tzdbg.tz_version = version; + + ret = qcom_scm_get_tz_feat_id_version(QCOM_SCM_FEAT_DIAG_ID, &version); + if (ret) { + pr_err("%s: scm_call to get tz diag version failed, ret = %d\n", + __func__, ret); + return ret; + } + pr_warn("tz diag version is %x\n", version); + if ( + (((version >> TZBSP_FVER_MAJOR_SHIFT) & TZBSP_FVER_MAJOR_MINOR_MASK) + == TZBSP_DIAG_MAJOR_VERSION_V9) && + (((version >> TZBSP_FVER_MINOR_SHIFT) & TZBSP_FVER_MAJOR_MINOR_MASK) + == TZBSP_DIAG_MINOR_VERSION_V2)) + tzdbg.is_enlarged_buf = true; else - tzdbg.tz_version = version; + tzdbg.is_enlarged_buf = false; + return ret; } static void tzdbg_query_encrypted_log(void) @@ -1257,7 +1417,7 @@ static void tzdbg_query_encrypted_log(void) pr_err("scm_call QUERY_ENCR_LOG_FEATURE failed ret %d\n", ret); tzdbg.is_encrypted_log_enabled = false; } else { - pr_info("encrypted qseelog enabled is %d\n", enabled); + pr_warn("encrypted qseelog enabled is %d\n", enabled); tzdbg.is_encrypted_log_enabled = enabled; } } @@ -1273,6 +1433,10 @@ static int tz_log_probe(struct platform_device *pdev) uint32_t *ptr = NULL; int ret = 0; + ret = tzdbg_get_tz_version(); + if (ret) + return ret; + /* * Get address that stores the physical location diagnostic data */ @@ -1346,19 +1510,10 @@ static int tz_log_probe(struct platform_device *pdev) tzdbg.diag_buf = (struct tzdbg_t *)ptr; } - /* allocate display_buf */ - display_buf_size = QSEE_LOG_BUF_SIZE * 4; - tzdbg.disp_buf = dma_alloc_coherent(&pdev->dev, display_buf_size, - &disp_buf_paddr, GFP_KERNEL); - if (tzdbg.disp_buf == NULL) { - ret = -ENOMEM; - goto exit_free_diag_buf; - } - /* register unencrypted qsee log buffer */ ret = tzdbg_register_qsee_log_buf(pdev); if (ret) - goto exit_free_disp_buf; + goto exit_free_diag_buf; /* allocate encrypted qsee and tz log buffer */ ret = tzdbg_allocate_encrypted_log_buf(pdev); @@ -1369,19 +1524,30 @@ static int tz_log_probe(struct platform_device *pdev) goto exit_free_qsee_log_buf; } - tzdbg_get_tz_version(); + /* allocate display_buf */ + if (UINT_MAX/4 < qseelog_buf_size) { + pr_err("display_buf_size integer overflow\n"); + goto exit_free_qsee_log_buf; + } + display_buf_size = qseelog_buf_size * 4; + tzdbg.disp_buf = dma_alloc_coherent(&pdev->dev, display_buf_size, + &disp_buf_paddr, GFP_KERNEL); + if (tzdbg.disp_buf == NULL) { + ret = -ENOMEM; + goto exit_free_encr_log_buf; + } if (tzdbgfs_init(pdev)) - goto exit_free_encr_log_buf; + goto exit_free_disp_buf; return 0; +exit_free_disp_buf: + dma_free_coherent(&pdev->dev, display_buf_size, + (void *)tzdbg.disp_buf, disp_buf_paddr); exit_free_encr_log_buf: tzdbg_free_encrypted_log_buf(pdev); exit_free_qsee_log_buf: tzdbg_free_qsee_log_buf(pdev); -exit_free_disp_buf: - dma_free_coherent(&pdev->dev, display_buf_size, - (void *)tzdbg.disp_buf, disp_buf_paddr); exit_free_diag_buf: if (!tzdbg.is_encrypted_log_enabled) kfree(tzdbg.diag_buf); diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c index 6364511b0354..be593d906590 100644 --- a/drivers/firmware/qcom_scm.c +++ b/drivers/firmware/qcom_scm.c @@ -912,6 +912,13 @@ int qcom_scm_get_tz_log_feat_id(u64 *version) } EXPORT_SYMBOL(qcom_scm_get_tz_log_feat_id); +int qcom_scm_get_tz_feat_id_version(u64 feat_id, u64 *version) +{ + return __qcom_scm_get_feat_version(__scm->dev, feat_id, + version); +} +EXPORT_SYMBOL(qcom_scm_get_tz_feat_id_version); + int qcom_scm_register_qsee_log_buf(phys_addr_t buf, size_t len) { return __qcom_scm_register_qsee_log_buf(__scm->dev, buf, len); diff --git a/include/linux/qcom_scm.h b/include/linux/qcom_scm.h index ce84f0da8c85..833d15d0d1b8 100644 --- a/include/linux/qcom_scm.h +++ b/include/linux/qcom_scm.h @@ -183,6 +183,7 @@ extern int qcom_scm_camera_protect_phy_lanes(bool protect, u64 regmask); extern int qcom_scm_tsens_reinit(int *tsens_ret); extern int qcom_scm_ice_restore_cfg(void); extern int qcom_scm_get_tz_log_feat_id(u64 *version); +extern int qcom_scm_get_tz_feat_id_version(u64 feat_id, u64 *version); extern int qcom_scm_register_qsee_log_buf(phys_addr_t buf, size_t len); extern int qcom_scm_query_encrypted_log_feature(u64 *enabled); extern int qcom_scm_request_encrypted_log(phys_addr_t buf, size_t len, @@ -346,6 +347,8 @@ static inline int qcom_scm_tsens_reinit(int *tsens_ret) static inline int qcom_scm_ice_restore_cfg(void) { return -ENODEV; } static inline int qcom_scm_get_tz_log_feat_id(u64 *version) { return -ENODEV; } +static inline int qcom_scm_get_tz_feat_id_version(u64 feat_id, u64 *version) + { return -ENODEV; } static inline int qcom_scm_register_qsee_log_buf(phys_addr_t buf, size_t len) { return -ENODEV; } static inline int qcom_scm_query_encrypted_log_feature(u64 *enabled)