1 /*
2 * Copyright (C) 2022 Huawei Technologies Co., Ltd.
3 * Decription: for tzdriver debug.
4 *
5 * This software is licensed under the terms of the GNU General Public
6 * License version 2, as published by the Free Software Foundation, and
7 * may be copied, distributed, and modified under those terms.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 */
14 #include "tzdebug.h"
15 #include <linux/workqueue.h>
16 #include <linux/kthread.h>
17 #include <linux/list.h>
18 #include <linux/sched.h>
19 #include <linux/delay.h>
20 #include <linux/mutex.h>
21 #include <linux/timer.h>
22 #include <linux/kernel.h>
23 #include <linux/uaccess.h>
24 #include <linux/debugfs.h>
25 #include <linux/module.h>
26 #include <linux/seq_file.h>
27 #include <linux/version.h>
28 #if LINUX_VERSION_CODE < KERNEL_VERSION(6, 6, 0)
29 #include <stdarg.h>
30 #else
31 #include <linux/stdarg.h>
32 #endif
33 #include <linux/mm.h>
34 #include <asm/tlbflush.h>
35 #include <asm/cacheflush.h>
36 #include <securec.h>
37 #include <asm/io.h>
38 #include "tc_ns_log.h"
39 #include "tc_ns_client.h"
40 #include "tc_client_driver.h"
41 #include "teek_ns_client.h"
42 #include "smc_smp.h"
43 #include "teek_client_constants.h"
44 #include "mailbox_mempool.h"
45 #include "tlogger.h"
46 #include "cmdmonitor.h"
47 #include "session_manager.h"
48 #include "internal_functions.h"
49
50 #define DEBUG_OPT_LEN 128
51
52 #ifdef CONFIG_TA_MEM_INUSE_ONLY
53 #define TA_MEMSTAT_ALL 0
54 #else
55 #define TA_MEMSTAT_ALL 1
56 #endif
57
58 static struct dentry *g_tz_dbg_dentry;
59
60 typedef void (*tzdebug_opt_func)(const char *param);
61
62 struct opt_ops {
63 char *name;
64 tzdebug_opt_func func;
65 };
66
67 static DEFINE_MUTEX(g_meminfo_lock);
68 static struct tee_mem g_tee_meminfo;
69 static void tzmemdump(const char *param);
send_dump_mem(int flag,int history,const struct tee_mem * statmem)70 static int send_dump_mem(int flag, int history, const struct tee_mem *statmem)
71 {
72 struct tc_ns_smc_cmd smc_cmd = { {0}, 0 };
73 struct mb_cmd_pack *mb_pack = NULL;
74 int ret = 0;
75
76 if (!statmem) {
77 tloge("statmem is NULL\n");
78 return -EINVAL;
79 }
80
81 mb_pack = mailbox_alloc_cmd_pack();
82 if (!mb_pack)
83 return -ENOMEM;
84
85 smc_cmd.cmd_id = GLOBAL_CMD_ID_DUMP_MEMINFO;
86 smc_cmd.cmd_type = CMD_TYPE_GLOBAL;
87 mb_pack->operation.paramtypes = teec_param_types(
88 TEE_PARAM_TYPE_MEMREF_INOUT, TEE_PARAM_TYPE_VALUE_INPUT,
89 TEE_PARAM_TYPE_NONE, TEE_PARAM_TYPE_NONE);
90 mb_pack->operation.params[0].memref.buffer = (unsigned int)mailbox_virt_to_phys((uintptr_t)statmem);
91 mb_pack->operation.params[0].memref.size = sizeof(*statmem);
92 mb_pack->operation.buffer_h_addr[0] =
93 (unsigned int)((uint64_t)mailbox_virt_to_phys((uintptr_t)statmem) >> ADDR_TRANS_NUM);
94 mb_pack->operation.params[1].value.a = (unsigned int)flag;
95 mb_pack->operation.params[1].value.b = (unsigned int)history;
96 smc_cmd.operation_phys =
97 (unsigned int)mailbox_virt_to_phys((uintptr_t)&mb_pack->operation);
98 smc_cmd.operation_h_phys =
99 (unsigned int)((uint64_t)mailbox_virt_to_phys((uintptr_t)&mb_pack->operation) >> ADDR_TRANS_NUM);
100
101 livepatch_down_read_sem();
102 if (tc_ns_smc(&smc_cmd) != 0) {
103 ret = -EPERM;
104 tloge("send dump mem failed\n");
105 }
106 livepatch_up_read_sem();
107
108 tz_log_write();
109 mailbox_free(mb_pack);
110 return ret;
111 }
112
tee_dump_mem(void)113 void tee_dump_mem(void)
114 {
115 tzmemdump(NULL);
116 if (tlogger_store_msg(CONFIG_TEE_LOG_ACHIVE_PATH,
117 sizeof(CONFIG_TEE_LOG_ACHIVE_PATH)) < 0)
118 tloge("[cmd_monitor_tick]tlogger store lastmsg failed\n");
119 }
120
121 /* get meminfo (tee_mem + N * ta_mem < 4Kbyte) from tee */
get_tee_meminfo_cmd(void)122 static int get_tee_meminfo_cmd(void)
123 {
124 int ret;
125 struct tee_mem *mem = NULL;
126
127 mem = mailbox_alloc(sizeof(*mem), MB_FLAG_ZERO);
128 if (!mem)
129 return -ENOMEM;
130
131 ret = send_dump_mem(0, TA_MEMSTAT_ALL, mem);
132 if (ret != 0) {
133 tloge("send dump failed\n");
134 mailbox_free(mem);
135 return ret;
136 }
137
138 mutex_lock(&g_meminfo_lock);
139 ret = memcpy_s(&g_tee_meminfo, sizeof(g_tee_meminfo), mem, sizeof(*mem));
140 if (ret != 0)
141 tloge("memcpy failed\n");
142
143 mutex_unlock(&g_meminfo_lock);
144 mailbox_free(mem);
145
146 return ret;
147 }
148
149 static atomic_t g_cmd_send = ATOMIC_INIT(1);
150
set_cmd_send_state(void)151 void set_cmd_send_state(void)
152 {
153 atomic_set(&g_cmd_send, 1);
154 }
155
get_tee_meminfo(struct tee_mem * meminfo)156 int get_tee_meminfo(struct tee_mem *meminfo)
157 {
158 errno_t s_ret;
159
160 if (!get_tz_init_flag()) return EFAULT;
161
162 if (!meminfo)
163 return -EINVAL;
164
165 if (atomic_read(&g_cmd_send) != 0) {
166 if (get_tee_meminfo_cmd() != 0)
167 return -EFAULT;
168 } else {
169 atomic_set(&g_cmd_send, 0);
170 }
171
172 mutex_lock(&g_meminfo_lock);
173 s_ret = memcpy_s(meminfo, sizeof(*meminfo),
174 &g_tee_meminfo, sizeof(g_tee_meminfo));
175 mutex_unlock(&g_meminfo_lock);
176 if (s_ret != 0)
177 return -1;
178
179 return 0;
180 }
181 EXPORT_SYMBOL(get_tee_meminfo);
182
tzdump(const char * param)183 static void tzdump(const char *param)
184 {
185 (void)param;
186 show_cmd_bitmap();
187 wakeup_tc_siq(SIQ_DUMP_SHELL);
188 }
189
tzmemdump(const char * param)190 static void tzmemdump(const char *param)
191 {
192 struct tee_mem *mem = NULL;
193
194 (void)param;
195 mem = mailbox_alloc(sizeof(*mem), MB_FLAG_ZERO);
196 if (!mem) {
197 tloge("mailbox alloc failed\n");
198 return;
199 }
200
201 if (send_dump_mem(1, 1, mem) != 0)
202 tloge("send dump mem failed\n");
203
204 mailbox_free(mem);
205 }
206
207 static struct opt_ops g_opt_arr[] = {
208 {"dump", tzdump},
209 {"memdump", tzmemdump},
210 {"dump_service", dump_services_status},
211 };
212
tz_dbg_opt_read(struct file * filp,char __user * ubuf,size_t cnt,loff_t * ppos)213 static ssize_t tz_dbg_opt_read(struct file *filp, char __user *ubuf,
214 size_t cnt, loff_t *ppos)
215 {
216 char *obuf = NULL;
217 char *p = NULL;
218 ssize_t ret;
219 uint32_t oboff = 0;
220 uint32_t i;
221
222 (void)(filp);
223
224 obuf = kzalloc(DEBUG_OPT_LEN, GFP_KERNEL);
225 if (ZERO_OR_NULL_PTR((unsigned long)(uintptr_t)obuf))
226 return -ENOMEM;
227 p = obuf;
228
229 for (i = 0; i < ARRAY_SIZE(g_opt_arr); i++) {
230 int len = snprintf_s(p, DEBUG_OPT_LEN - oboff, DEBUG_OPT_LEN -oboff -1,
231 "%s ", g_opt_arr[i].name);
232 if (len < 0) {
233 kfree(obuf);
234 tloge("snprintf opt name of idx %d failed\n", i);
235 return -EINVAL;
236 }
237 p += len;
238 oboff += (uint32_t)len;
239 }
240 obuf[oboff - 1] = '\n';
241
242 ret = simple_read_from_buffer(ubuf, cnt, ppos, obuf, oboff);
243 kfree(obuf);
244
245 return ret;
246 }
247
tz_dbg_opt_write(struct file * filp,const char __user * ubuf,size_t cnt,loff_t * ppos)248 static ssize_t tz_dbg_opt_write(struct file *filp,
249 const char __user *ubuf, size_t cnt, loff_t *ppos)
250 {
251 char buf[128] = {0};
252 char *value = NULL;
253 char *p = NULL;
254 uint32_t i = 0;
255
256 if (!ubuf || !filp || !ppos)
257 return -EINVAL;
258
259 if (cnt >= sizeof(buf))
260 return -EINVAL;
261
262 if (cnt == 0)
263 return -EINVAL;
264
265 if (copy_from_user(buf, ubuf, cnt) != 0)
266 return -EFAULT;
267
268 buf[cnt] = 0;
269 if (cnt > 0 && buf[cnt -1] == '\n')
270 buf[cnt - 1] = 0;
271 value = buf;
272 p = strsep(&value, ":"); /* when buf has no :, value may be NULL */
273 if (!p)
274 return -EINVAL;
275
276 for (i = 0; i < ARRAY_SIZE(g_opt_arr); i++) {
277 if ((strncmp(p, g_opt_arr[i].name,
278 strlen(g_opt_arr[i].name)) ==0) &&
279 strlen(p) == strlen(g_opt_arr[i].name)) {
280 g_opt_arr[i].func(value);
281 return (ssize_t)cnt;
282 }
283 }
284 return -EFAULT;
285 }
286
287 static const struct file_operations g_tz_dbg_opt_fops = {
288 .owner = THIS_MODULE,
289 .read = tz_dbg_opt_read,
290 .write = tz_dbg_opt_write,
291 };
292
293 #ifdef CONFIG_MEMSTAT_DEBUGFS
memstat_debug_show(struct seq_file * m,void * v)294 static int memstat_debug_show(struct seq_file *m, void *v)
295 {
296 struct tee_mem *mem_stat = NULL;
297 int ret;
298 uint32_t i;
299 (void)v;
300
301 mem_stat = kzalloc(sizeof(*mem_stat), GFP_KERNEL);
302 if (ZERO_OR_NULL_PTR((unsigned long)(uintptr_t)mem_stat))
303 return -ENOMEM;
304
305 ret = get_tee_meminfo(mem_stat);
306 if (ret != 0) {
307 tloge("get tee meminfo failed\n");
308 kfree(mem_stat);
309 mem_stat = NULL;
310 return -EINVAL;
311 }
312
313 seq_printf(m, "TotalMem:%u Pmem:%u Free_Mem:%u Free_Mem_Min:%u TA_Num:%u\n",
314 mem_stat->total_mem, mem_stat->pmem, mem_stat->free_mem, mem_stat->free_mem_min, mem_stat->ta_num);
315
316 for (i = 0; i < mem_stat->ta_num; i++)
317 seq_printf(m, "ta_name:%s ta_pmem:%u pmem_max:%u pmem_limit:%u\n",
318 mem_stat->ta_mem_info[i].ta_name, mem_stat->ta_mem_info[i].pmem,
319 mem_stat->ta_mem_info[i].pmem_max, mem_stat->ta_mem_info[i].pmem_limit);
320
321 kfree(mem_stat);
322 mem_stat = NULL;
323 return 0;
324 }
325
tz_memstat_open(struct inode * inode,struct file * file)326 static int tz_memstat_open(struct inode *inode, struct file *file)
327 {
328 (void)inode;
329 return single_open(file, memstat_debug_show, NULL);
330 }
331
332 static const struct file_operations g_tz_dbg_memstat_fops = {
333 .owner = THIS_MODULE,
334 .open = tz_memstat_open,
335 .read = seq_read,
336 .llseek = seq_lseek,
337 .release = single_release,
338 };
339 #endif
340
341 #ifdef CONFIG_TEE_TRACE
tee_trace_event_show(struct seq_file * m,void * v)342 static int tee_trace_event_show(struct seq_file *m, void *v)
343 {
344 struct tee_trace_view_t view = { 0, 0, 0, 0, { 0 }, { 0 } };
345 struct trace_log_info log_info;
346 (void)v;
347
348 get_tee_trace_start(&view);
349 if (view.buffer_is_full == 1)
350 seq_printf(m, "Total Trace Events: %u (Notice: Buffer is full)\n", view.total);
351 else
352 seq_printf(m, "Total Trace Events: %u\n", view.total);
353
354 if (view.total > 0) {
355 uint32_t i = 0;
356
357 while (get_tee_trace_next(&view, &log_info, false) != -1) {
358 uint32_t task_ca = (uint32_t)(log_info.add_info);
359 uint32_t task_idx = (uint32_t)(log_info.add_info >> 32);
360
361 if (log_info.event_id == SCHED_IN || log_info.event_id == SCHED_OUT) {
362 seq_printf(m, "[%4u][cpu%3u][ca-%5u] %10llu : %s %u %s\n",
363 i++, log_info.cpu, log_info.ca_pid, log_info.time, log_info.event_name,
364 task_ca, get_tee_trace_task_name(task_idx));
365 } else {
366 seq_printf(m, "[%4u][cpu%3u][ca-%5u] %10llu : %s %llu\n",
367 i++, log_info.cpu, log_info.ca_pid, log_info.time, log_info.event_name,
368 log_info.add_info);
369 }
370 }
371 }
372
373 return 0;
374 }
375
tee_trace_event_open(struct inode * inode,struct file * file)376 static int tee_trace_event_open(struct inode *inode, struct file *file)
377 {
378 return single_open(file, tee_trace_event_show, NULL);
379 }
380
381 struct tee_trace_cmd_t {
382 const char *cmd;
383 int (*func)(void);
384 } tee_trace_cmd[] = {
385 {"start", tee_trace_event_start},
386 {"loop_record", tee_trace_event_start_loop_record},
387 {"stop", tee_trace_event_stop}
388 };
389
tee_trace_event_write(struct file * filp,const char __user * ubuf,size_t cnt,loff_t * ppos)390 static ssize_t tee_trace_event_write(struct file *filp,
391 const char __user *ubuf, size_t cnt, loff_t *ppos)
392 {
393 char buf[32] = {0};
394 uint32_t i = 0;
395
396 if (cnt >= sizeof(buf))
397 return -EINVAL;
398
399 if (copy_from_user(buf, ubuf, cnt))
400 return -EINVAL;
401
402 buf[cnt] = 0;
403 if (cnt > 0 && buf[cnt - 1] == '\n')
404 buf[cnt - 1] = 0;
405
406 for (i = 0; i < ARRAY_SIZE(tee_trace_cmd); i++) {
407 if (!strncmp(buf, tee_trace_cmd[i].cmd,
408 strlen(tee_trace_cmd[i].cmd))) {
409 tee_trace_cmd[i].func();
410 return cnt;
411 }
412 }
413 return -EINVAL;
414 }
415
416 static const struct file_operations tee_trace_event_fops = {
417 .owner = THIS_MODULE,
418 .open = tee_trace_event_open,
419 .read = seq_read,
420 .write = tee_trace_event_write,
421 .llseek = seq_lseek,
422 .release = single_release,
423 };
424 #endif
425
tzdebug_init(void)426 int tzdebug_init(void)
427 {
428 #if defined(DEF_ENG) || defined(CONFIG_TZDRIVER_MODULE)
429 g_tz_dbg_dentry = debugfs_create_dir("tzdebug", NULL);
430 if (!g_tz_dbg_dentry)
431 return -1;
432
433 debugfs_create_file("opt", 0660, g_tz_dbg_dentry, NULL,
434 &g_tz_dbg_opt_fops);
435
436 #ifdef CONFIG_MEMSTAT_DEBUGFS
437 debugfs_create_file("memstat", 0444, g_tz_dbg_dentry, NULL,
438 &g_tz_dbg_memstat_fops);
439 #endif
440
441 #ifdef CONFIG_TEE_TRACE
442 debugfs_create_file("tee_trace", 0660, g_tz_dbg_dentry, NULL,
443 &tee_trace_event_fops);
444 tee_trace_event_enable();
445 #endif
446
447 #else
448 (void)g_tz_dbg_dentry;
449 (void)g_tz_dbg_opt_fops;
450 #endif
451 return 0;
452 }
453
free_tzdebug(void)454 void free_tzdebug(void)
455 {
456 #if defined(DEF_ENG) || defined(CONFIG_TZDRIVER_MODULE)
457 if (!g_tz_dbg_dentry)
458 return;
459
460 debugfs_remove_recursive(g_tz_dbg_dentry);
461 g_tz_dbg_dentry = NULL;
462 #endif
463 }