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