diff --git a/tz_log/tz_log.c b/tz_log/tz_log.c index 902cfa9671..c0aa22eb66 100644 --- a/tz_log/tz_log.c +++ b/tz_log/tz_log.c @@ -3,6 +3,9 @@ * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. */ + +#define pr_fmt(fmt) "%s:[%s][%d]: " fmt, KBUILD_MODNAME, __func__, __LINE__ + #include #include #include @@ -21,6 +24,10 @@ #include #include #include +#if IS_ENABLED(CONFIG_MSM_TMECOM_QMP) +#include +#endif + #include "misc/qseecomi.h" /* QSEE_LOG_BUF_SIZE = 32K */ @@ -29,6 +36,9 @@ /* enlarged qsee log buf size is 128K by default */ #define QSEE_LOG_BUF_SIZE_V2 0x20000 +/* Tme log buffer size 20K */ +#define TME_LOG_BUF_SIZE 0x5000 + /* TZ Diagnostic Area legacy version number */ #define TZBSP_DIAG_MAJOR_VERSION_LEGACY 2 @@ -376,6 +386,11 @@ struct hypdbg_t { uint8_t log_buf_p[]; }; +struct tme_log_pos { + uint32_t offset; + size_t size; +}; + /* * Enumeration order for VMID's */ @@ -390,6 +405,7 @@ enum tzdbg_stats_type { TZDBG_HYP_GENERAL, TZDBG_HYP_LOG, TZDBG_RM_LOG, + TZDBG_TME_LOG, TZDBG_STATS_MAX }; @@ -404,9 +420,11 @@ struct tzdbg { void __iomem *virt_iobase; void __iomem *hyp_virt_iobase; void __iomem *rmlog_virt_iobase; + void __iomem *tmelog_virt_iobase; struct tzdbg_t *diag_buf; struct hypdbg_t *hyp_diag_buf; uint8_t *rm_diag_buf; + uint8_t *tme_buf; char *disp_buf; int debug_tz[TZDBG_STATS_MAX]; struct tzdbg_stat stat[TZDBG_STATS_MAX]; @@ -459,6 +477,7 @@ static struct tzdbg tzdbg = { .stat[TZDBG_HYP_GENERAL].name = "hyp_general", .stat[TZDBG_HYP_LOG].name = "hyp_log", .stat[TZDBG_RM_LOG].name = "rm_log", + .stat[TZDBG_TME_LOG].name = "tme_log", }; static struct tzdbg_log_t *g_qsee_log; @@ -468,6 +487,7 @@ 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 uint32_t tmecrashdump_address_offset; static uint64_t qseelog_shmbridge_handle; static struct encrypted_log_info enc_qseelog_info; @@ -1176,6 +1196,65 @@ static int _disp_hyp_general_stats(size_t count) return len; } +#if IS_ENABLED(CONFIG_MSM_TMECOM_QMP) +static int _disp_tme_log_stats(size_t count) +{ + static struct tme_log_pos log_start = { 0 }; + static bool wrap_around = { false }; + uint32_t buf_size; + uint8_t *log_ptr = NULL; + uint32_t log_len = 0; + int ret = 0; + + /* Return 0 to close file in case some error in initialising step. */ + if (!tzdbg.tmelog_virt_iobase || !tmecrashdump_address_offset) + return 0; + + /* Return 0 to close the display file */ + if ((log_start.size == 0x0) && wrap_around) { + wrap_around = false; + return 0; + } + + /* Copy TME log data to tzdbg diag buffer for the first time */ + if (!wrap_around) { + if (tmelog_process_request(tmecrashdump_address_offset, + TME_LOG_BUF_SIZE, &buf_size)) { + pr_err("Read tme log failed, ret=%d, buf_size: %#x\n", ret, buf_size); + return 0; + } + log_start.offset = 0x0; + log_start.size = buf_size; + } + + log_ptr = tzdbg.tmelog_virt_iobase; + log_len = log_start.size; + log_ptr += log_start.offset; + + /* Check if we exceed the max length provided by user space */ + log_len = min(min((uint32_t)count, log_len), display_buf_size); + + log_start.size -= log_len; + log_start.offset += log_len; + pr_debug("log_len: %d, log_start.offset: %#x, log_start.size: %#x\n", + log_len, log_start.offset, log_start.size); + + if (log_start.size) + wrap_around = true; + + /* Copy TME log data to display buffer */ + memcpy_fromio(tzdbg.disp_buf, log_ptr, log_len); + + tzdbg.stat[TZDBG_TME_LOG].data = tzdbg.disp_buf; + return log_len; +} +#else +static int _disp_tme_log_stats(size_t count) +{ + return 0; +} +#endif + static ssize_t tzdbg_fs_read_unencrypted(int tz_id, char __user *buf, size_t count, loff_t *offp) { @@ -1232,6 +1311,10 @@ static ssize_t tzdbg_fs_read_unencrypted(int tz_id, char __user *buf, len = _disp_rm_log_stats(count); *offp = 0; break; + case TZDBG_TME_LOG: + len = _disp_tme_log_stats(count); + *offp = 0; + break; default: break; } @@ -1298,7 +1381,7 @@ static ssize_t tzdbg_fs_read(struct file *file, char __user *buf, if (!tzdbg.is_encrypted_log_enabled || (tz_id == TZDBG_HYP_GENERAL || tz_id == TZDBG_HYP_LOG) - || tz_id == TZDBG_RM_LOG) + || tz_id == TZDBG_RM_LOG || tz_id == TZDBG_TME_LOG) return tzdbg_fs_read_unencrypted(tz_id, buf, count, offp); else return tzdbg_fs_read_encrypted(tz_id, buf, count, offp); @@ -1327,6 +1410,31 @@ struct proc_ops tzdbg_fops = { .proc_release = tzdbg_procfs_release, }; +static int tzdbg_init_tme_log(struct platform_device *pdev, void __iomem *virt_iobase) +{ + /* + * Tme logs are dumped in tme log ddr region but that region is not + * accessible to hlos. Instead, collect logs at tme crashdump ddr + * region with tmecom interface and then display logs reading from + * crashdump region. + */ + if (of_property_read_u32((&pdev->dev)->of_node, "tmecrashdump-address-offset", + &tmecrashdump_address_offset)) { + pr_err("Tme Crashdump address offset need to be defined!\n"); + return -EINVAL; + } + + tzdbg.tmelog_virt_iobase = + devm_ioremap(&pdev->dev, tmecrashdump_address_offset, TME_LOG_BUF_SIZE); + if (!tzdbg.tmelog_virt_iobase) { + pr_err("ERROR: Could not ioremap: start=%#x, len=%u\n", + tmecrashdump_address_offset, TME_LOG_BUF_SIZE); + return -ENXIO; + } + + return 0; +} + /* * Allocates log buffer from ION, registers the buffer at TZ */ @@ -1785,6 +1893,11 @@ static int tz_log_probe(struct platform_device *pdev) } } + /* Init for tme log */ + ret = tzdbg_init_tme_log(pdev, virt_iobase); + if (ret < 0) + pr_warn("Tme log initialization failed!\n"); + /* register unencrypted qsee log buffer */ ret = tzdbg_register_qsee_log_buf(pdev); if (ret)