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 }