1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (c) 2014, STMicroelectronics International N.V.
4  */
5 
6 #if defined(__KERNEL__)
7 #include <platform_config.h>
8 #endif
9 
10 #include <printk.h>
11 #include <stdarg.h>
12 #include <string.h>
13 #include <trace.h>
14 #include <util.h>
15 #include <types_ext.h>
16 
17 #if (TRACE_LEVEL < TRACE_MIN) || (TRACE_LEVEL > TRACE_MAX)
18 #error "Invalid value of TRACE_LEVEL"
19 #endif
20 
21 #if (TRACE_LEVEL >= TRACE_ERROR)
22 
trace_set_level(int level)23 void trace_set_level(int level)
24 {
25 	if (((int)level >= TRACE_MIN) && (level <= TRACE_MAX))
26 		trace_level = level;
27 	else
28 		trace_level = TRACE_MAX;
29 }
30 
trace_get_level(void)31 int trace_get_level(void)
32 {
33 	return trace_level;
34 }
35 
trace_level_to_string(int level,bool level_ok)36 static char trace_level_to_string(int level, bool level_ok)
37 {
38 	/*
39 	 * U = Unused
40 	 * E = Error
41 	 * I = Information
42 	 * D = Debug
43 	 * F = Flow
44 	 */
45 	static const char lvl_strs[] = { 'U', 'E', 'I', 'D', 'F' };
46 	int l = 0;
47 
48 	if (!level_ok)
49 		return 'M';
50 
51 	if ((level >= TRACE_MIN) && (level <= TRACE_MAX))
52 		l = level;
53 
54 	return lvl_strs[l];
55 }
56 
print_thread_id(char * buf,size_t bs)57 static int print_thread_id(char *buf, size_t bs)
58 {
59 #if CFG_NUM_THREADS > 100
60 	int num_thread_digits = 3;
61 #elif CFG_NUM_THREADS > 10
62 	int num_thread_digits = 2;
63 #else
64 	int num_thread_digits = 1;
65 #endif
66 	int thread_id = trace_ext_get_thread_id();
67 
68 	if (thread_id >= 0)
69 		return snprintk(buf, bs, "%0*d ", num_thread_digits, thread_id);
70 	else
71 		return snprintk(buf, bs, "%*s ", num_thread_digits, "");
72 }
73 
74 #if defined(__KERNEL__)
print_core_id(char * buf,size_t bs)75 static int print_core_id(char *buf, size_t bs)
76 {
77 #if CFG_TEE_CORE_NB_CORE > 100
78 	const int num_digits = 3;
79 	const char qm[] = "???";
80 #elif CFG_TEE_CORE_NB_CORE > 10
81 	const int num_digits = 2;
82 	const char qm[] = "??";
83 #else
84 	const int num_digits = 1;
85 	const char qm[] = "?";
86 #endif
87 	int core_id = trace_ext_get_core_id();
88 
89 	if (core_id >= 0)
90 		return snprintk(buf, bs, "%0*u ", num_digits, core_id);
91 	else
92 		return snprintk(buf, bs, "%s ", qm);
93 }
94 #else  /* defined(__KERNEL__) */
print_core_id(char * buf __unused,size_t bs __unused)95 static int print_core_id(char *buf __unused, size_t bs __unused)
96 {
97 	return 0;
98 }
99 #endif
100 
101 /* Format trace of user ta. Inline with kernel ta */
trace_printf(const char * function,int line,int level,bool level_ok,const char * fmt,...)102 void trace_printf(const char *function, int line, int level, bool level_ok,
103 		  const char *fmt, ...)
104 {
105 	va_list ap;
106 
107 	va_start(ap, fmt);
108 	trace_vprintf(function, line, level, level_ok, fmt, ap);
109 	va_end(ap);
110 }
trace_vprintf(const char * function,int line,int level,bool level_ok,const char * fmt,va_list ap)111 void trace_vprintf(const char *function, int line, int level, bool level_ok,
112 		   const char *fmt, va_list ap)
113 {
114 	char buf[MAX_PRINT_SIZE];
115 	size_t boffs = 0;
116 	int res;
117 
118 	if (level_ok && level > trace_level)
119 		return;
120 
121 	/* Print the type of message */
122 	res = snprintk(buf, sizeof(buf), "%c/",
123 		       trace_level_to_string(level, level_ok));
124 	if (res < 0)
125 		return;
126 	boffs += res;
127 
128 	/* Print the location, i.e., TEE core or TA */
129 	res = snprintk(buf + boffs, sizeof(buf) - boffs, "%s:",
130 		       trace_ext_prefix);
131 	if (res < 0)
132 		return;
133 	boffs += res;
134 
135 	if (level_ok && (BIT(level) & CFG_MSG_LONG_PREFIX_MASK)) {
136 		/* Print the core ID if in atomic context  */
137 		res = print_core_id(buf + boffs, sizeof(buf) - boffs);
138 		if (res < 0)
139 			return;
140 		boffs += res;
141 
142 		/* Print the Thread ID */
143 		res = print_thread_id(buf + boffs, sizeof(buf) - boffs);
144 		if (res < 0)
145 			return;
146 		boffs += res;
147 
148 		if (function) {
149 			res = snprintk(buf + boffs, sizeof(buf) - boffs, "%s:%d ",
150 				       function, line);
151 			if (res < 0)
152 				return;
153 			boffs += res;
154 		}
155 	} else {
156 		/* Add space after location info */
157 		if (boffs >= sizeof(buf) - 1)
158 		    return;
159 		buf[boffs++] = ' ';
160 		buf[boffs] = 0;
161 	}
162 
163 	res = vsnprintk(buf + boffs, sizeof(buf) - boffs, fmt, ap);
164 	if (res > 0)
165 		boffs += res;
166 
167 	if (boffs >= (sizeof(buf) - 1))
168 		boffs = sizeof(buf) - 2;
169 
170 	buf[boffs] = '\n';
171 	while (boffs && buf[boffs] == '\n')
172 		boffs--;
173 	boffs++;
174 	buf[boffs + 1] = '\0';
175 
176 	trace_ext_puts(buf);
177 }
178 
179 #else
180 
181 /*
182  * In case we have a zero or negative trace level when compiling optee_os, we
183  * have to add stubs to trace functions in case they are used with TA having a
184  * non-zero trace level
185  */
186 
trace_set_level(int level __unused)187 void trace_set_level(int level __unused)
188 {
189 }
190 
trace_get_level(void)191 int trace_get_level(void)
192 {
193 	return 0;
194 }
195 
trace_printf(const char * function __unused,int line __unused,int level __unused,bool level_ok __unused,const char * fmt __unused,...)196 void trace_printf(const char *function __unused, int line __unused,
197 		  int level __unused, bool level_ok __unused,
198 		  const char *fmt __unused, ...)
199 {
200 }
201 
202 #endif
203 
204 #if (TRACE_LEVEL >= TRACE_DEBUG)
205 struct strbuf {
206 	char buf[MAX_PRINT_SIZE];
207 	char *ptr;
208 };
209 
append(struct strbuf * sbuf,const char * fmt,...)210 static int __printf(2, 3) append(struct strbuf *sbuf, const char *fmt, ...)
211 {
212 	int left;
213 	int len;
214 	va_list ap;
215 
216 	if (sbuf->ptr == NULL)
217 		sbuf->ptr = sbuf->buf;
218 	left = sizeof(sbuf->buf) - (sbuf->ptr - sbuf->buf);
219 	va_start(ap, fmt);
220 	len = vsnprintk(sbuf->ptr, left, fmt, ap);
221 	va_end(ap);
222 	if (len < 0) {
223 		/* Format error */
224 		return 0;
225 	}
226 	if (len >= left) {
227 		/* Output was truncated */
228 		return 0;
229 	}
230 	sbuf->ptr += MIN(left, len);
231 	return 1;
232 }
233 
dhex_dump(const char * function,int line,int level,const void * buf,int len)234 void dhex_dump(const char *function, int line, int level,
235 	       const void *buf, int len)
236 {
237 	int i;
238 	int ok;
239 	struct strbuf sbuf;
240 	char *in = (char *)buf;
241 
242 	if (level <= trace_level) {
243 		sbuf.ptr = NULL;
244 		for (i = 0; i < len; i++) {
245 			if ((i % 16) == 0) {
246 				ok = append(&sbuf, "%0*" PRIxVA "  ",
247 					    PRIxVA_WIDTH, (vaddr_t)(in + i));
248 				if (!ok)
249 					goto err;
250 			}
251 			ok = append(&sbuf, "%02x ", in[i]);
252 			if (!ok)
253 				goto err;
254 			if ((i % 16) == 7) {
255 				ok = append(&sbuf, " ");
256 				if (!ok)
257 					goto err;
258 			} else if ((i % 16) == 15) {
259 				trace_printf(function, line, level, true, "%s",
260 					     sbuf.buf);
261 				sbuf.ptr = NULL;
262 			}
263 		}
264 		if (sbuf.ptr) {
265 			/* Buffer is not empty: flush it */
266 			trace_printf(function, line, level, true, "%s",
267 				     sbuf.buf);
268 
269 		}
270 	}
271 	return;
272 err:
273 	DMSG("Hex dump error");
274 }
275 #else
276 
277 /*
278  * In case we have trace level less than debug when compiling optee_os, we have
279  * to add stubs to trace functions in case they are used with TA having a
280  * a higher trace level
281  */
282 
dhex_dump(const char * function __unused,int line __unused,int level __unused,const void * buf __unused,int len __unused)283 void dhex_dump(const char *function __unused, int line __unused,
284 	       int level __unused,
285 	       const void *buf __unused, int len __unused)
286 {
287 }
288 
289 #endif
290