1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (c) 2011 The Chromium OS Authors.
4 */
5
6#include <common.h>
7#include <command.h>
8#include <env.h>
9#include <mapmem.h>
10#include <trace.h>
11#include <asm/io.h>
12
13static int get_args(int argc, char *const argv[], char **buff,
14		    size_t *buff_ptr, size_t *buff_size)
15{
16	if (argc < 2)
17		return -1;
18	if (argc < 4) {
19		*buff_size = env_get_ulong("profsize", 16, 0);
20		*buff = map_sysmem(env_get_ulong("profbase", 16, 0),
21				   *buff_size);
22		*buff_ptr = env_get_ulong("profoffset", 16, 0);
23	} else {
24		*buff_size = hextoul(argv[3], NULL);
25		*buff = map_sysmem(hextoul(argv[2], NULL),
26				   *buff_size);
27		*buff_ptr = 0;
28	};
29	return 0;
30}
31
32static int create_func_list(int argc, char *const argv[])
33{
34	size_t buff_size, avail, buff_ptr, needed, used;
35	char *buff;
36	int err;
37
38	if (get_args(argc, argv, &buff, &buff_ptr, &buff_size))
39		return -1;
40
41	avail = buff_size - buff_ptr;
42	err = trace_list_functions(buff + buff_ptr, avail, &needed);
43	if (err)
44		printf("Error: truncated (%#zx bytes needed)\n", needed);
45	used = min(avail, (size_t)needed);
46	printf("Function trace dumped to %08lx, size %#zx\n",
47	       (ulong)map_to_sysmem(buff + buff_ptr), used);
48	env_set_hex("profbase", map_to_sysmem(buff));
49	env_set_hex("profsize", buff_size);
50	env_set_hex("profoffset", buff_ptr + used);
51
52	return 0;
53}
54
55static int create_call_list(int argc, char *const argv[])
56{
57	size_t buff_size, avail, buff_ptr, needed, used;
58	char *buff;
59	int err;
60
61	if (get_args(argc, argv, &buff, &buff_ptr, &buff_size))
62		return -1;
63
64	avail = buff_size - buff_ptr;
65	err = trace_list_calls(buff + buff_ptr, avail, &needed);
66	if (err)
67		printf("Error: truncated (%#zx bytes needed)\n", needed);
68	used = min(avail, (size_t)needed);
69	printf("Call list dumped to %08lx, size %#zx\n",
70	       (ulong)map_to_sysmem(buff + buff_ptr), used);
71
72	env_set_hex("profbase", map_to_sysmem(buff));
73	env_set_hex("profsize", buff_size);
74	env_set_hex("profoffset", buff_ptr + used);
75
76	return 0;
77}
78
79int do_trace(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
80{
81	const char *cmd = argc < 2 ? NULL : argv[1];
82
83	if (!cmd)
84		return cmd_usage(cmdtp);
85	switch (*cmd) {
86	case 'p':
87		trace_set_enabled(0);
88		break;
89	case 'c':
90		if (create_call_list(argc, argv))
91			return cmd_usage(cmdtp);
92		break;
93	case 'r':
94		trace_set_enabled(1);
95		break;
96	case 'f':
97		if (create_func_list(argc, argv))
98			return cmd_usage(cmdtp);
99		break;
100	case 's':
101		trace_print_stats();
102		break;
103	default:
104		return CMD_RET_USAGE;
105	}
106
107	return 0;
108}
109
110U_BOOT_CMD(
111	trace,	4,	1,	do_trace,
112	"trace utility commands",
113	"stats                        - display tracing statistics\n"
114	"trace pause                        - pause tracing\n"
115	"trace resume                       - resume tracing\n"
116	"trace funclist [<addr> <size>]     - dump function list into buffer\n"
117	"trace calls  [<addr> <size>]       "
118		"- dump function call trace into buffer"
119);
120