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