• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 }