Loading drivers/firmware/qcom/tz_log.c +357 −55 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. */ #include <linux/debugfs.h> #include <linux/errno.h> Loading @@ -23,6 +23,9 @@ /* 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) /* TZ Diagnostic Area legacy version number */ #define TZBSP_DIAG_MAJOR_VERSION_LEGACY 2 /* Loading Loading @@ -58,6 +61,9 @@ #define TZBSP_NONCE_LEN 12 #define TZBSP_TAG_LEN 16 #define ENCRYPTED_TZ_LOG_ID 0 #define ENCRYPTED_QSEE_LOG_ID 1 /* * VMID Table */ Loading Loading @@ -285,6 +291,8 @@ enum tzdbg_stats_type { }; struct tzdbg_stat { size_t display_len; size_t display_offset; char *name; char *data; }; Loading @@ -300,6 +308,33 @@ struct tzdbg { uint32_t hyp_debug_rw_buf_size; bool is_hyplog_enabled; uint32_t tz_version; bool is_encrypted_log_enabled; }; struct tzbsp_encr_log_t { /* Magic Number */ uint32_t magic_num; /* version NUMBER */ uint32_t version; /* encrypted log size */ uint32_t encr_log_buff_size; /* Wrap value*/ uint16_t wrap_count; /* AES encryption key wrapped up with oem public key*/ uint8_t key[TZBSP_AES_256_ENCRYPTED_KEY_SIZE]; /* Nonce used for encryption*/ uint8_t nonce[TZBSP_NONCE_LEN]; /* Tag to be used for Validation */ uint8_t tag[TZBSP_TAG_LEN]; /* Encrypted log buffer */ uint8_t log_buf[1]; }; struct encrypted_log_info { phys_addr_t paddr; void *vaddr; size_t size; uint64_t shmb_handle; }; static struct tzdbg tzdbg = { Loading @@ -317,7 +352,12 @@ static struct tzdbg tzdbg = { static struct tzdbg_log_t *g_qsee_log; static dma_addr_t coh_pmem; static uint32_t debug_rw_buf_size; static uint32_t display_buf_size; static phys_addr_t disp_buf_paddr; static uint64_t qseelog_shmbridge_handle; static struct encrypted_log_info enc_qseelog_info; static struct encrypted_log_info enc_tzlog_info; /* * Debugfs data structure and functions Loading Loading @@ -704,6 +744,87 @@ static int __disp_hyp_log_stats(uint8_t *log, return len; } static int print_text(char *intro_message, unsigned char *text_addr, unsigned int size, char *buf, uint32_t buf_len) { unsigned int i; int len = 0; pr_debug("begin address %p, size %d\n", text_addr, size); len += scnprintf(buf + len, buf_len - len, "%s\n", intro_message); for (i = 0; i < size; i++) { if (buf_len <= len + 6) { pr_err("buffer not enough, buf_len %d, len %d\n", buf_len, len); return buf_len; } len += scnprintf(buf + len, buf_len - len, "%02hhx ", text_addr[i]); if ((i & 0x1f) == 0x1f) len += scnprintf(buf + len, buf_len - len, "%c", '\n'); } len += scnprintf(buf + len, buf_len - len, "%c", '\n'); return len; } static int _disp_encrpted_log_stats(struct encrypted_log_info *enc_log_info, enum tzdbg_stats_type type, uint32_t log_id) { int ret = 0, len = 0; struct tzbsp_encr_log_t *encr_log_head; uint32_t size = 0; ret = qcom_scm_request_encrypted_log(enc_log_info->paddr, enc_log_info->size, log_id); if (ret) return 0; encr_log_head = (struct tzbsp_encr_log_t *)(enc_log_info->vaddr); pr_debug("display_buf_size = %d, encr_log_buff_size = %d\n", display_buf_size, encr_log_head->encr_log_buff_size); size = encr_log_head->encr_log_buff_size; len += scnprintf(tzdbg.disp_buf + len, (display_buf_size - 1) - len, "\n-------- New Encrypted %s --------\n", ((log_id == ENCRYPTED_QSEE_LOG_ID) ? "QSEE Log" : "TZ Dialog")); len += scnprintf(tzdbg.disp_buf + len, (display_buf_size - 1) - len, "\nMagic_Num :\n0x%x\n" "\nVerion :\n%d\n" "\nEncr_Log_Buff_Size :\n%d\n" "\nWrap_Count :\n%d\n", encr_log_head->magic_num, encr_log_head->version, encr_log_head->encr_log_buff_size, encr_log_head->wrap_count); len += print_text("\nKey : ", encr_log_head->key, TZBSP_AES_256_ENCRYPTED_KEY_SIZE, tzdbg.disp_buf + len, display_buf_size); len += print_text("\nNonce : ", encr_log_head->nonce, TZBSP_NONCE_LEN, tzdbg.disp_buf + len, display_buf_size - len); len += print_text("\nTag : ", encr_log_head->tag, TZBSP_TAG_LEN, tzdbg.disp_buf + len, display_buf_size - len); if (len > display_buf_size - size) pr_warn("Cannot fit all info into the buffer\n"); pr_debug("encrypted log size %d, disply buffer size %d, used len %d\n", size, display_buf_size, len); len += print_text("\nLog : ", encr_log_head->log_buf, size, tzdbg.disp_buf + len, display_buf_size - len); memset(enc_log_info->vaddr, 0, enc_log_info->size); tzdbg.stat[type].data = tzdbg.disp_buf; return len; } static int _disp_tz_log_stats(size_t count) { static struct tzdbg_log_pos_t log_start = {0}; Loading Loading @@ -774,23 +895,24 @@ static int _disp_hyp_general_stats(size_t count) return len; } static ssize_t tzdbgfs_read(struct file *file, char __user *buf, static ssize_t tzdbgfs_read_unencrypted(struct file *file, char __user *buf, size_t count, loff_t *offp) { int len = 0; int *tz_id = file->private_data; int tz_id = *(int *)(file->private_data); 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) 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) memcpy_fromio((void *)tzdbg.diag_buf, tzdbg.virt_iobase, debug_rw_buf_size); if (*tz_id == TZDBG_HYP_GENERAL || *tz_id == TZDBG_HYP_LOG) memcpy_fromio((void *)tzdbg.hyp_diag_buf, tzdbg.hyp_virt_iobase, if (tz_id == TZDBG_HYP_GENERAL || tz_id == TZDBG_HYP_LOG) memcpy_fromio((void *)tzdbg.hyp_diag_buf, tzdbg.hyp_virt_iobase, tzdbg.hyp_debug_rw_buf_size); switch (*tz_id) { switch (tz_id) { case TZDBG_BOOT: len = _disp_tz_boot_stats(); break; Loading Loading @@ -834,7 +956,60 @@ static ssize_t tzdbgfs_read(struct file *file, char __user *buf, len = count; return simple_read_from_buffer(buf, len, offp, tzdbg.stat[(*tz_id)].data, len); tzdbg.stat[tz_id].data, len); } static ssize_t tzdbgfs_read_encrypted(struct file *file, char __user *buf, size_t count, loff_t *offp) { int len = 0, ret = 0; int tz_id = *(int *)(file->private_data); struct tzdbg_stat *stat = &(tzdbg.stat[tz_id]); pr_debug("tz_id = %d\n", tz_id); if (tz_id >= TZDBG_STATS_MAX) { pr_err("invalid encrypted log id %d\n", tz_id); return ret; } if (!stat->display_len) { if (tz_id == TZDBG_QSEE_LOG) stat->display_len = _disp_encrpted_log_stats( &enc_qseelog_info, tz_id, ENCRYPTED_QSEE_LOG_ID); else stat->display_len = _disp_encrpted_log_stats( &enc_tzlog_info, tz_id, ENCRYPTED_TZ_LOG_ID); stat->display_offset = 0; } len = stat->display_len; if (len > count) len = count; *offp = 0; ret = simple_read_from_buffer(buf, len, offp, tzdbg.stat[tz_id].data + stat->display_offset, count); stat->display_offset += ret; stat->display_len -= ret; pr_debug("ret = %d, offset = %d\n", ret, (int)(*offp)); pr_debug("display_len = %d, offset = %d\n", stat->display_len, stat->display_offset); return ret; } static ssize_t tzdbgfs_read(struct file *file, char __user *buf, size_t count, loff_t *offp) { int tz_id = *(int *)(file->private_data); if (!tzdbg.is_encrypted_log_enabled || (tz_id == TZDBG_HYP_GENERAL || tz_id == TZDBG_HYP_LOG)) return tzdbgfs_read_unencrypted(file, buf, count, offp); else return tzdbgfs_read_encrypted(file, buf, count, offp); } static const struct file_operations tzdbg_fops = { Loading @@ -846,7 +1021,7 @@ static const struct file_operations tzdbg_fops = { /* * Allocates log buffer from ION, registers the buffer at TZ */ static void tzdbg_register_qsee_log_buf(struct platform_device *pdev) static int tzdbg_register_qsee_log_buf(struct platform_device *pdev) { size_t len = QSEE_LOG_BUF_SIZE; int ret = 0; Loading @@ -857,35 +1032,118 @@ static void tzdbg_register_qsee_log_buf(struct platform_device *pdev) buf = dma_alloc_coherent(&pdev->dev, len, &coh_pmem, GFP_KERNEL); if (buf == NULL) return; return -ENOMEM; if (!tzdbg.is_encrypted_log_enabled) { ret = qtee_shmbridge_register(coh_pmem, len, ns_vmids, ns_vm_perms, ns_vm_nums, PERM_READ | PERM_WRITE, &qseelog_shmbridge_handle); PERM_READ | PERM_WRITE, &qseelog_shmbridge_handle); if (ret) { pr_err("failed to create bridge for qsee_log buffer\n"); dma_free_coherent(&pdev->dev, len, (void *)g_qsee_log, coh_pmem); return; pr_err("failed to create bridge for qsee_log buf\n"); goto exit_free_mem; } } 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); if (ret != QSEOS_RESULT_SUCCESS) { pr_err( "%s: scm_call to register log buf failed, resp result =%lld\n", __func__, ret); goto err; goto exit_dereg_bridge; } g_qsee_log->log_pos.wrap = g_qsee_log->log_pos.offset = 0; return; return ret; err: 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); 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); } static int tzdbg_allocate_encrypted_log_buf(struct platform_device *pdev) { int ret = 0; uint32_t ns_vmids[] = {VMID_HLOS}; uint32_t ns_vm_perms[] = {PERM_READ | PERM_WRITE}; uint32_t ns_vm_nums = 1; if (!tzdbg.is_encrypted_log_enabled) return 0; enc_qseelog_info.size = MAX_ENCR_LOG_BUFF_SIZE; enc_qseelog_info.vaddr = dma_alloc_coherent(&pdev->dev, enc_qseelog_info.size, &enc_qseelog_info.paddr, GFP_KERNEL); if (enc_qseelog_info.vaddr == NULL) return -ENOMEM; ret = qtee_shmbridge_register(enc_qseelog_info.paddr, enc_qseelog_info.size, ns_vmids, ns_vm_perms, ns_vm_nums, PERM_READ | PERM_WRITE, &enc_qseelog_info.shmb_handle); if (ret) { pr_err("failed to create encr_qsee_log bridge, ret %d\n", ret); goto exit_free_qseelog; } pr_debug("Alloc memory for encr_qsee_log, size = %zu\n", enc_qseelog_info.size); enc_tzlog_info.size = debug_rw_buf_size; enc_tzlog_info.vaddr = dma_alloc_coherent(&pdev->dev, enc_tzlog_info.size, &enc_tzlog_info.paddr, GFP_KERNEL); if (enc_tzlog_info.vaddr == NULL) goto exit_unreg_qseelog; ret = qtee_shmbridge_register(enc_tzlog_info.paddr, enc_tzlog_info.size, ns_vmids, ns_vm_perms, ns_vm_nums, PERM_READ | PERM_WRITE, &enc_tzlog_info.shmb_handle); if (ret) { pr_err("failed to create encr_tz_log bridge, ret = %d\n", ret); goto exit_free_tzlog; } pr_debug("Alloc memory for encr_tz_log, size %zu\n", enc_qseelog_info.size); return 0; exit_free_tzlog: dma_free_coherent(&pdev->dev, enc_tzlog_info.size, enc_tzlog_info.vaddr, enc_tzlog_info.paddr); exit_unreg_qseelog: qtee_shmbridge_deregister(enc_qseelog_info.shmb_handle); exit_free_qseelog: dma_free_coherent(&pdev->dev, enc_qseelog_info.size, enc_qseelog_info.vaddr, enc_qseelog_info.paddr); return -ENOMEM; } static void tzdbg_free_encrypted_log_buf(struct platform_device *pdev) { qtee_shmbridge_deregister(enc_tzlog_info.shmb_handle); dma_free_coherent(&pdev->dev, enc_tzlog_info.size, enc_tzlog_info.vaddr, enc_tzlog_info.paddr); qtee_shmbridge_deregister(enc_qseelog_info.shmb_handle); dma_free_coherent(&pdev->dev, enc_qseelog_info.size, enc_qseelog_info.vaddr, enc_qseelog_info.paddr); } static int tzdbgfs_init(struct platform_device *pdev) { int rc = 0; Loading @@ -910,11 +1168,6 @@ static int tzdbgfs_init(struct platform_device *pdev) goto err; } } tzdbg.disp_buf = kzalloc(max(debug_rw_buf_size, tzdbg.hyp_debug_rw_buf_size), GFP_KERNEL); if (tzdbg.disp_buf == NULL) goto err; platform_set_drvdata(pdev, dent_dir); return 0; err: Loading Loading @@ -994,6 +1247,21 @@ static void tzdbg_get_tz_version(void) tzdbg.tz_version = version; } static void tzdbg_query_encrypted_log(void) { int ret = 0; uint64_t enabled; ret = qcom_scm_query_encrypted_log_feature(&enabled); if (ret) { 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); tzdbg.is_encrypted_log_enabled = enabled; } } /* * Driver functions */ Loading Loading @@ -1039,12 +1307,13 @@ static int tz_log_probe(struct platform_device *pdev) if (tzdbg.is_hyplog_enabled) { ret = __update_hypdbg_base(pdev, virt_iobase); if (ret) { dev_err(&pdev->dev, "%s() failed to get device tree data ret = %d\n", dev_err(&pdev->dev, "%s: fail to get hypdbg_base ret %d\n", __func__, ret); return -EINVAL; } } else { dev_info(&pdev->dev, "Hyp log service is not supported\n"); dev_info(&pdev->dev, "Hyp log service not support\n"); } } else { dev_dbg(&pdev->dev, "Device tree data is not found\n"); Loading @@ -1055,46 +1324,79 @@ static int tz_log_probe(struct platform_device *pdev) */ tzdiag_phy_iobase = readl_relaxed(virt_iobase); tzdbg_query_encrypted_log(); /* * Map the diagnostic information area * Map the diagnostic information area if encryption is disabled */ if (!tzdbg.is_encrypted_log_enabled) { tzdbg.virt_iobase = devm_ioremap_nocache(&pdev->dev, tzdiag_phy_iobase, debug_rw_buf_size); if (!tzdbg.virt_iobase) { dev_err(&pdev->dev, "%s: ERROR could not ioremap: start=%pr, len=%u\n", "%s: could not ioremap: start=%pr, len=%u\n", __func__, &tzdiag_phy_iobase, debug_rw_buf_size); return -ENXIO; } /* allocate diag_buf */ ptr = kzalloc(debug_rw_buf_size, GFP_KERNEL); if (ptr == NULL) return -ENOMEM; tzdbg.diag_buf = (struct tzdbg_t *)ptr; } if (tzdbgfs_init(pdev)) goto err; /* 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; } tzdbg_register_qsee_log_buf(pdev); /* register unencrypted qsee log buffer */ ret = tzdbg_register_qsee_log_buf(pdev); if (ret) goto exit_free_disp_buf; /* allocate encrypted qsee and tz log buffer */ ret = tzdbg_allocate_encrypted_log_buf(pdev); if (ret) { dev_err(&pdev->dev, "Failed to allocate encrypted log buffer\n", __func__); goto exit_free_qsee_log_buf; } tzdbg_get_tz_version(); if (tzdbgfs_init(pdev)) goto exit_free_encr_log_buf; return 0; err: 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); return -ENXIO; } static int tz_log_remove(struct platform_device *pdev) { kzfree(tzdbg.diag_buf); kzfree(tzdbg.hyp_diag_buf); tzdbgfs_exit(pdev); tzdbg_free_encrypted_log_buf(pdev); tzdbg_free_qsee_log_buf(pdev); dma_free_coherent(&pdev->dev, display_buf_size, (void *)tzdbg.disp_buf, disp_buf_paddr); if (!tzdbg.is_encrypted_log_enabled) kfree(tzdbg.diag_buf); return 0; } Loading drivers/firmware/qcom_scm-smc.c +38 −0 Original line number Diff line number Diff line Loading @@ -1924,6 +1924,44 @@ int __qcom_scm_register_qsee_log_buf(struct device *dev, phys_addr_t buf, return ret ? : desc.res[0]; } int __qcom_scm_query_encrypted_log_feature(struct device *dev, u64 *enabled) { int ret; struct qcom_scm_desc desc = { .svc = QCOM_SCM_SVC_QSEELOG, .cmd = QCOM_SCM_QUERY_ENCR_LOG_FEAT_ID, .owner = ARM_SMCCC_OWNER_TRUSTED_OS }; desc.arginfo = QCOM_SCM_ARGS(0); ret = qcom_scm_call(dev, &desc); if (enabled) *enabled = desc.res[0]; return ret; } int __qcom_scm_request_encrypted_log(struct device *dev, phys_addr_t buf, size_t len, uint32_t log_id) { int ret; struct qcom_scm_desc desc = { .svc = QCOM_SCM_SVC_QSEELOG, .cmd = QCOM_SCM_REQUEST_ENCR_LOG_ID, .owner = ARM_SMCCC_OWNER_TRUSTED_OS }; desc.args[0] = buf; desc.args[1] = len; desc.args[2] = log_id; desc.arginfo = QCOM_SCM_ARGS(3, QCOM_SCM_RW); ret = qcom_scm_call(dev, &desc); return ret ? : desc.res[0]; } int __qcom_scm_invoke_smc(struct device *dev, phys_addr_t in_buf, size_t in_buf_size, phys_addr_t out_buf, size_t out_buf_size, int32_t *result, u64 *response_type, unsigned int *data) Loading drivers/firmware/qcom_scm.c +13 −0 Original line number Diff line number Diff line Loading @@ -918,6 +918,19 @@ int qcom_scm_register_qsee_log_buf(phys_addr_t buf, size_t len) } EXPORT_SYMBOL(qcom_scm_register_qsee_log_buf); int qcom_scm_query_encrypted_log_feature(u64 *enabled) { return __qcom_scm_query_encrypted_log_feature(__scm->dev, enabled); } EXPORT_SYMBOL(qcom_scm_query_encrypted_log_feature); int qcom_scm_request_encrypted_log(phys_addr_t buf, size_t len, uint32_t log_id) { return __qcom_scm_request_encrypted_log(__scm->dev, buf, len, log_id); } EXPORT_SYMBOL(qcom_scm_request_encrypted_log); int qcom_scm_invoke_smc(phys_addr_t in_buf, size_t in_buf_size, phys_addr_t out_buf, size_t out_buf_size, int32_t *result, u64 *response_type, unsigned int *data) Loading drivers/firmware/qcom_scm.h +6 −0 Original line number Diff line number Diff line Loading @@ -238,6 +238,12 @@ extern int __qcom_scm_tsens_reinit(struct device *dev, int *tsens_ret); extern int __qcom_scm_register_qsee_log_buf(struct device *dev, phys_addr_t buf, size_t len); #define QCOM_SCM_FEAT_LOG_ID 0x0a #define QCOM_SCM_QUERY_ENCR_LOG_FEAT_ID 0x0b extern int __qcom_scm_query_encrypted_log_feature(struct device *dev, u64 *enabled); #define QCOM_SCM_REQUEST_ENCR_LOG_ID 0x0c extern int __qcom_scm_request_encrypted_log(struct device *dev, phys_addr_t buf, size_t len, uint32_t log_id); #define QCOM_SCM_SVC_KEYSTORE 0x05 #define QCOM_SCM_ICE_RESTORE_KEY_ID 0x06 Loading include/linux/qcom_scm.h +8 −0 Original line number Diff line number Diff line Loading @@ -184,6 +184,9 @@ 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_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, uint32_t log_id); extern int qcom_scm_invoke_smc(phys_addr_t in_buf, size_t in_buf_size, phys_addr_t out_buf, size_t out_buf_size, int32_t *result, u64 *response_type, unsigned int *data); Loading Loading @@ -345,6 +348,11 @@ static inline int qcom_scm_get_tz_log_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) { return -ENODEV; } static inline int qcom_scm_request_encrypted_log(phys_addr_t buf, size_t len, uint32_t log_id) { return -ENODEV; } static inline int qcom_scm_invoke_smc(phys_addr_t in_buf, size_t in_buf_size, phys_addr_t out_buf, size_t out_buf_size, int32_t *result, u64 *request_type, unsigned int *data) { return -ENODEV; } Loading Loading
drivers/firmware/qcom/tz_log.c +357 −55 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. */ #include <linux/debugfs.h> #include <linux/errno.h> Loading @@ -23,6 +23,9 @@ /* 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) /* TZ Diagnostic Area legacy version number */ #define TZBSP_DIAG_MAJOR_VERSION_LEGACY 2 /* Loading Loading @@ -58,6 +61,9 @@ #define TZBSP_NONCE_LEN 12 #define TZBSP_TAG_LEN 16 #define ENCRYPTED_TZ_LOG_ID 0 #define ENCRYPTED_QSEE_LOG_ID 1 /* * VMID Table */ Loading Loading @@ -285,6 +291,8 @@ enum tzdbg_stats_type { }; struct tzdbg_stat { size_t display_len; size_t display_offset; char *name; char *data; }; Loading @@ -300,6 +308,33 @@ struct tzdbg { uint32_t hyp_debug_rw_buf_size; bool is_hyplog_enabled; uint32_t tz_version; bool is_encrypted_log_enabled; }; struct tzbsp_encr_log_t { /* Magic Number */ uint32_t magic_num; /* version NUMBER */ uint32_t version; /* encrypted log size */ uint32_t encr_log_buff_size; /* Wrap value*/ uint16_t wrap_count; /* AES encryption key wrapped up with oem public key*/ uint8_t key[TZBSP_AES_256_ENCRYPTED_KEY_SIZE]; /* Nonce used for encryption*/ uint8_t nonce[TZBSP_NONCE_LEN]; /* Tag to be used for Validation */ uint8_t tag[TZBSP_TAG_LEN]; /* Encrypted log buffer */ uint8_t log_buf[1]; }; struct encrypted_log_info { phys_addr_t paddr; void *vaddr; size_t size; uint64_t shmb_handle; }; static struct tzdbg tzdbg = { Loading @@ -317,7 +352,12 @@ static struct tzdbg tzdbg = { static struct tzdbg_log_t *g_qsee_log; static dma_addr_t coh_pmem; static uint32_t debug_rw_buf_size; static uint32_t display_buf_size; static phys_addr_t disp_buf_paddr; static uint64_t qseelog_shmbridge_handle; static struct encrypted_log_info enc_qseelog_info; static struct encrypted_log_info enc_tzlog_info; /* * Debugfs data structure and functions Loading Loading @@ -704,6 +744,87 @@ static int __disp_hyp_log_stats(uint8_t *log, return len; } static int print_text(char *intro_message, unsigned char *text_addr, unsigned int size, char *buf, uint32_t buf_len) { unsigned int i; int len = 0; pr_debug("begin address %p, size %d\n", text_addr, size); len += scnprintf(buf + len, buf_len - len, "%s\n", intro_message); for (i = 0; i < size; i++) { if (buf_len <= len + 6) { pr_err("buffer not enough, buf_len %d, len %d\n", buf_len, len); return buf_len; } len += scnprintf(buf + len, buf_len - len, "%02hhx ", text_addr[i]); if ((i & 0x1f) == 0x1f) len += scnprintf(buf + len, buf_len - len, "%c", '\n'); } len += scnprintf(buf + len, buf_len - len, "%c", '\n'); return len; } static int _disp_encrpted_log_stats(struct encrypted_log_info *enc_log_info, enum tzdbg_stats_type type, uint32_t log_id) { int ret = 0, len = 0; struct tzbsp_encr_log_t *encr_log_head; uint32_t size = 0; ret = qcom_scm_request_encrypted_log(enc_log_info->paddr, enc_log_info->size, log_id); if (ret) return 0; encr_log_head = (struct tzbsp_encr_log_t *)(enc_log_info->vaddr); pr_debug("display_buf_size = %d, encr_log_buff_size = %d\n", display_buf_size, encr_log_head->encr_log_buff_size); size = encr_log_head->encr_log_buff_size; len += scnprintf(tzdbg.disp_buf + len, (display_buf_size - 1) - len, "\n-------- New Encrypted %s --------\n", ((log_id == ENCRYPTED_QSEE_LOG_ID) ? "QSEE Log" : "TZ Dialog")); len += scnprintf(tzdbg.disp_buf + len, (display_buf_size - 1) - len, "\nMagic_Num :\n0x%x\n" "\nVerion :\n%d\n" "\nEncr_Log_Buff_Size :\n%d\n" "\nWrap_Count :\n%d\n", encr_log_head->magic_num, encr_log_head->version, encr_log_head->encr_log_buff_size, encr_log_head->wrap_count); len += print_text("\nKey : ", encr_log_head->key, TZBSP_AES_256_ENCRYPTED_KEY_SIZE, tzdbg.disp_buf + len, display_buf_size); len += print_text("\nNonce : ", encr_log_head->nonce, TZBSP_NONCE_LEN, tzdbg.disp_buf + len, display_buf_size - len); len += print_text("\nTag : ", encr_log_head->tag, TZBSP_TAG_LEN, tzdbg.disp_buf + len, display_buf_size - len); if (len > display_buf_size - size) pr_warn("Cannot fit all info into the buffer\n"); pr_debug("encrypted log size %d, disply buffer size %d, used len %d\n", size, display_buf_size, len); len += print_text("\nLog : ", encr_log_head->log_buf, size, tzdbg.disp_buf + len, display_buf_size - len); memset(enc_log_info->vaddr, 0, enc_log_info->size); tzdbg.stat[type].data = tzdbg.disp_buf; return len; } static int _disp_tz_log_stats(size_t count) { static struct tzdbg_log_pos_t log_start = {0}; Loading Loading @@ -774,23 +895,24 @@ static int _disp_hyp_general_stats(size_t count) return len; } static ssize_t tzdbgfs_read(struct file *file, char __user *buf, static ssize_t tzdbgfs_read_unencrypted(struct file *file, char __user *buf, size_t count, loff_t *offp) { int len = 0; int *tz_id = file->private_data; int tz_id = *(int *)(file->private_data); 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) 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) memcpy_fromio((void *)tzdbg.diag_buf, tzdbg.virt_iobase, debug_rw_buf_size); if (*tz_id == TZDBG_HYP_GENERAL || *tz_id == TZDBG_HYP_LOG) memcpy_fromio((void *)tzdbg.hyp_diag_buf, tzdbg.hyp_virt_iobase, if (tz_id == TZDBG_HYP_GENERAL || tz_id == TZDBG_HYP_LOG) memcpy_fromio((void *)tzdbg.hyp_diag_buf, tzdbg.hyp_virt_iobase, tzdbg.hyp_debug_rw_buf_size); switch (*tz_id) { switch (tz_id) { case TZDBG_BOOT: len = _disp_tz_boot_stats(); break; Loading Loading @@ -834,7 +956,60 @@ static ssize_t tzdbgfs_read(struct file *file, char __user *buf, len = count; return simple_read_from_buffer(buf, len, offp, tzdbg.stat[(*tz_id)].data, len); tzdbg.stat[tz_id].data, len); } static ssize_t tzdbgfs_read_encrypted(struct file *file, char __user *buf, size_t count, loff_t *offp) { int len = 0, ret = 0; int tz_id = *(int *)(file->private_data); struct tzdbg_stat *stat = &(tzdbg.stat[tz_id]); pr_debug("tz_id = %d\n", tz_id); if (tz_id >= TZDBG_STATS_MAX) { pr_err("invalid encrypted log id %d\n", tz_id); return ret; } if (!stat->display_len) { if (tz_id == TZDBG_QSEE_LOG) stat->display_len = _disp_encrpted_log_stats( &enc_qseelog_info, tz_id, ENCRYPTED_QSEE_LOG_ID); else stat->display_len = _disp_encrpted_log_stats( &enc_tzlog_info, tz_id, ENCRYPTED_TZ_LOG_ID); stat->display_offset = 0; } len = stat->display_len; if (len > count) len = count; *offp = 0; ret = simple_read_from_buffer(buf, len, offp, tzdbg.stat[tz_id].data + stat->display_offset, count); stat->display_offset += ret; stat->display_len -= ret; pr_debug("ret = %d, offset = %d\n", ret, (int)(*offp)); pr_debug("display_len = %d, offset = %d\n", stat->display_len, stat->display_offset); return ret; } static ssize_t tzdbgfs_read(struct file *file, char __user *buf, size_t count, loff_t *offp) { int tz_id = *(int *)(file->private_data); if (!tzdbg.is_encrypted_log_enabled || (tz_id == TZDBG_HYP_GENERAL || tz_id == TZDBG_HYP_LOG)) return tzdbgfs_read_unencrypted(file, buf, count, offp); else return tzdbgfs_read_encrypted(file, buf, count, offp); } static const struct file_operations tzdbg_fops = { Loading @@ -846,7 +1021,7 @@ static const struct file_operations tzdbg_fops = { /* * Allocates log buffer from ION, registers the buffer at TZ */ static void tzdbg_register_qsee_log_buf(struct platform_device *pdev) static int tzdbg_register_qsee_log_buf(struct platform_device *pdev) { size_t len = QSEE_LOG_BUF_SIZE; int ret = 0; Loading @@ -857,35 +1032,118 @@ static void tzdbg_register_qsee_log_buf(struct platform_device *pdev) buf = dma_alloc_coherent(&pdev->dev, len, &coh_pmem, GFP_KERNEL); if (buf == NULL) return; return -ENOMEM; if (!tzdbg.is_encrypted_log_enabled) { ret = qtee_shmbridge_register(coh_pmem, len, ns_vmids, ns_vm_perms, ns_vm_nums, PERM_READ | PERM_WRITE, &qseelog_shmbridge_handle); PERM_READ | PERM_WRITE, &qseelog_shmbridge_handle); if (ret) { pr_err("failed to create bridge for qsee_log buffer\n"); dma_free_coherent(&pdev->dev, len, (void *)g_qsee_log, coh_pmem); return; pr_err("failed to create bridge for qsee_log buf\n"); goto exit_free_mem; } } 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); if (ret != QSEOS_RESULT_SUCCESS) { pr_err( "%s: scm_call to register log buf failed, resp result =%lld\n", __func__, ret); goto err; goto exit_dereg_bridge; } g_qsee_log->log_pos.wrap = g_qsee_log->log_pos.offset = 0; return; return ret; err: 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); 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); } static int tzdbg_allocate_encrypted_log_buf(struct platform_device *pdev) { int ret = 0; uint32_t ns_vmids[] = {VMID_HLOS}; uint32_t ns_vm_perms[] = {PERM_READ | PERM_WRITE}; uint32_t ns_vm_nums = 1; if (!tzdbg.is_encrypted_log_enabled) return 0; enc_qseelog_info.size = MAX_ENCR_LOG_BUFF_SIZE; enc_qseelog_info.vaddr = dma_alloc_coherent(&pdev->dev, enc_qseelog_info.size, &enc_qseelog_info.paddr, GFP_KERNEL); if (enc_qseelog_info.vaddr == NULL) return -ENOMEM; ret = qtee_shmbridge_register(enc_qseelog_info.paddr, enc_qseelog_info.size, ns_vmids, ns_vm_perms, ns_vm_nums, PERM_READ | PERM_WRITE, &enc_qseelog_info.shmb_handle); if (ret) { pr_err("failed to create encr_qsee_log bridge, ret %d\n", ret); goto exit_free_qseelog; } pr_debug("Alloc memory for encr_qsee_log, size = %zu\n", enc_qseelog_info.size); enc_tzlog_info.size = debug_rw_buf_size; enc_tzlog_info.vaddr = dma_alloc_coherent(&pdev->dev, enc_tzlog_info.size, &enc_tzlog_info.paddr, GFP_KERNEL); if (enc_tzlog_info.vaddr == NULL) goto exit_unreg_qseelog; ret = qtee_shmbridge_register(enc_tzlog_info.paddr, enc_tzlog_info.size, ns_vmids, ns_vm_perms, ns_vm_nums, PERM_READ | PERM_WRITE, &enc_tzlog_info.shmb_handle); if (ret) { pr_err("failed to create encr_tz_log bridge, ret = %d\n", ret); goto exit_free_tzlog; } pr_debug("Alloc memory for encr_tz_log, size %zu\n", enc_qseelog_info.size); return 0; exit_free_tzlog: dma_free_coherent(&pdev->dev, enc_tzlog_info.size, enc_tzlog_info.vaddr, enc_tzlog_info.paddr); exit_unreg_qseelog: qtee_shmbridge_deregister(enc_qseelog_info.shmb_handle); exit_free_qseelog: dma_free_coherent(&pdev->dev, enc_qseelog_info.size, enc_qseelog_info.vaddr, enc_qseelog_info.paddr); return -ENOMEM; } static void tzdbg_free_encrypted_log_buf(struct platform_device *pdev) { qtee_shmbridge_deregister(enc_tzlog_info.shmb_handle); dma_free_coherent(&pdev->dev, enc_tzlog_info.size, enc_tzlog_info.vaddr, enc_tzlog_info.paddr); qtee_shmbridge_deregister(enc_qseelog_info.shmb_handle); dma_free_coherent(&pdev->dev, enc_qseelog_info.size, enc_qseelog_info.vaddr, enc_qseelog_info.paddr); } static int tzdbgfs_init(struct platform_device *pdev) { int rc = 0; Loading @@ -910,11 +1168,6 @@ static int tzdbgfs_init(struct platform_device *pdev) goto err; } } tzdbg.disp_buf = kzalloc(max(debug_rw_buf_size, tzdbg.hyp_debug_rw_buf_size), GFP_KERNEL); if (tzdbg.disp_buf == NULL) goto err; platform_set_drvdata(pdev, dent_dir); return 0; err: Loading Loading @@ -994,6 +1247,21 @@ static void tzdbg_get_tz_version(void) tzdbg.tz_version = version; } static void tzdbg_query_encrypted_log(void) { int ret = 0; uint64_t enabled; ret = qcom_scm_query_encrypted_log_feature(&enabled); if (ret) { 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); tzdbg.is_encrypted_log_enabled = enabled; } } /* * Driver functions */ Loading Loading @@ -1039,12 +1307,13 @@ static int tz_log_probe(struct platform_device *pdev) if (tzdbg.is_hyplog_enabled) { ret = __update_hypdbg_base(pdev, virt_iobase); if (ret) { dev_err(&pdev->dev, "%s() failed to get device tree data ret = %d\n", dev_err(&pdev->dev, "%s: fail to get hypdbg_base ret %d\n", __func__, ret); return -EINVAL; } } else { dev_info(&pdev->dev, "Hyp log service is not supported\n"); dev_info(&pdev->dev, "Hyp log service not support\n"); } } else { dev_dbg(&pdev->dev, "Device tree data is not found\n"); Loading @@ -1055,46 +1324,79 @@ static int tz_log_probe(struct platform_device *pdev) */ tzdiag_phy_iobase = readl_relaxed(virt_iobase); tzdbg_query_encrypted_log(); /* * Map the diagnostic information area * Map the diagnostic information area if encryption is disabled */ if (!tzdbg.is_encrypted_log_enabled) { tzdbg.virt_iobase = devm_ioremap_nocache(&pdev->dev, tzdiag_phy_iobase, debug_rw_buf_size); if (!tzdbg.virt_iobase) { dev_err(&pdev->dev, "%s: ERROR could not ioremap: start=%pr, len=%u\n", "%s: could not ioremap: start=%pr, len=%u\n", __func__, &tzdiag_phy_iobase, debug_rw_buf_size); return -ENXIO; } /* allocate diag_buf */ ptr = kzalloc(debug_rw_buf_size, GFP_KERNEL); if (ptr == NULL) return -ENOMEM; tzdbg.diag_buf = (struct tzdbg_t *)ptr; } if (tzdbgfs_init(pdev)) goto err; /* 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; } tzdbg_register_qsee_log_buf(pdev); /* register unencrypted qsee log buffer */ ret = tzdbg_register_qsee_log_buf(pdev); if (ret) goto exit_free_disp_buf; /* allocate encrypted qsee and tz log buffer */ ret = tzdbg_allocate_encrypted_log_buf(pdev); if (ret) { dev_err(&pdev->dev, "Failed to allocate encrypted log buffer\n", __func__); goto exit_free_qsee_log_buf; } tzdbg_get_tz_version(); if (tzdbgfs_init(pdev)) goto exit_free_encr_log_buf; return 0; err: 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); return -ENXIO; } static int tz_log_remove(struct platform_device *pdev) { kzfree(tzdbg.diag_buf); kzfree(tzdbg.hyp_diag_buf); tzdbgfs_exit(pdev); tzdbg_free_encrypted_log_buf(pdev); tzdbg_free_qsee_log_buf(pdev); dma_free_coherent(&pdev->dev, display_buf_size, (void *)tzdbg.disp_buf, disp_buf_paddr); if (!tzdbg.is_encrypted_log_enabled) kfree(tzdbg.diag_buf); return 0; } Loading
drivers/firmware/qcom_scm-smc.c +38 −0 Original line number Diff line number Diff line Loading @@ -1924,6 +1924,44 @@ int __qcom_scm_register_qsee_log_buf(struct device *dev, phys_addr_t buf, return ret ? : desc.res[0]; } int __qcom_scm_query_encrypted_log_feature(struct device *dev, u64 *enabled) { int ret; struct qcom_scm_desc desc = { .svc = QCOM_SCM_SVC_QSEELOG, .cmd = QCOM_SCM_QUERY_ENCR_LOG_FEAT_ID, .owner = ARM_SMCCC_OWNER_TRUSTED_OS }; desc.arginfo = QCOM_SCM_ARGS(0); ret = qcom_scm_call(dev, &desc); if (enabled) *enabled = desc.res[0]; return ret; } int __qcom_scm_request_encrypted_log(struct device *dev, phys_addr_t buf, size_t len, uint32_t log_id) { int ret; struct qcom_scm_desc desc = { .svc = QCOM_SCM_SVC_QSEELOG, .cmd = QCOM_SCM_REQUEST_ENCR_LOG_ID, .owner = ARM_SMCCC_OWNER_TRUSTED_OS }; desc.args[0] = buf; desc.args[1] = len; desc.args[2] = log_id; desc.arginfo = QCOM_SCM_ARGS(3, QCOM_SCM_RW); ret = qcom_scm_call(dev, &desc); return ret ? : desc.res[0]; } int __qcom_scm_invoke_smc(struct device *dev, phys_addr_t in_buf, size_t in_buf_size, phys_addr_t out_buf, size_t out_buf_size, int32_t *result, u64 *response_type, unsigned int *data) Loading
drivers/firmware/qcom_scm.c +13 −0 Original line number Diff line number Diff line Loading @@ -918,6 +918,19 @@ int qcom_scm_register_qsee_log_buf(phys_addr_t buf, size_t len) } EXPORT_SYMBOL(qcom_scm_register_qsee_log_buf); int qcom_scm_query_encrypted_log_feature(u64 *enabled) { return __qcom_scm_query_encrypted_log_feature(__scm->dev, enabled); } EXPORT_SYMBOL(qcom_scm_query_encrypted_log_feature); int qcom_scm_request_encrypted_log(phys_addr_t buf, size_t len, uint32_t log_id) { return __qcom_scm_request_encrypted_log(__scm->dev, buf, len, log_id); } EXPORT_SYMBOL(qcom_scm_request_encrypted_log); int qcom_scm_invoke_smc(phys_addr_t in_buf, size_t in_buf_size, phys_addr_t out_buf, size_t out_buf_size, int32_t *result, u64 *response_type, unsigned int *data) Loading
drivers/firmware/qcom_scm.h +6 −0 Original line number Diff line number Diff line Loading @@ -238,6 +238,12 @@ extern int __qcom_scm_tsens_reinit(struct device *dev, int *tsens_ret); extern int __qcom_scm_register_qsee_log_buf(struct device *dev, phys_addr_t buf, size_t len); #define QCOM_SCM_FEAT_LOG_ID 0x0a #define QCOM_SCM_QUERY_ENCR_LOG_FEAT_ID 0x0b extern int __qcom_scm_query_encrypted_log_feature(struct device *dev, u64 *enabled); #define QCOM_SCM_REQUEST_ENCR_LOG_ID 0x0c extern int __qcom_scm_request_encrypted_log(struct device *dev, phys_addr_t buf, size_t len, uint32_t log_id); #define QCOM_SCM_SVC_KEYSTORE 0x05 #define QCOM_SCM_ICE_RESTORE_KEY_ID 0x06 Loading
include/linux/qcom_scm.h +8 −0 Original line number Diff line number Diff line Loading @@ -184,6 +184,9 @@ 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_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, uint32_t log_id); extern int qcom_scm_invoke_smc(phys_addr_t in_buf, size_t in_buf_size, phys_addr_t out_buf, size_t out_buf_size, int32_t *result, u64 *response_type, unsigned int *data); Loading Loading @@ -345,6 +348,11 @@ static inline int qcom_scm_get_tz_log_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) { return -ENODEV; } static inline int qcom_scm_request_encrypted_log(phys_addr_t buf, size_t len, uint32_t log_id) { return -ENODEV; } static inline int qcom_scm_invoke_smc(phys_addr_t in_buf, size_t in_buf_size, phys_addr_t out_buf, size_t out_buf_size, int32_t *result, u64 *request_type, unsigned int *data) { return -ENODEV; } Loading