1 /* 2 * Copyright (c) 2014, STMicroelectronics International N.V. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, 9 * this list of conditions and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above copyright notice, 12 * this list of conditions and the following disclaimer in the documentation 13 * and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 19 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 * POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 #include <printk.h> 29 #include <stdarg.h> 30 #include <string.h> 31 #include <trace.h> 32 #include <util.h> 33 #include <types_ext.h> 34 35 #if (TRACE_LEVEL > 0) 36 37 #if (TRACE_LEVEL < TRACE_MIN) || (TRACE_LEVEL > TRACE_MAX) 38 #error "Invalid value of TRACE_LEVEL" 39 #endif 40 41 void trace_set_level(int level) 42 { 43 if (((int)level >= TRACE_MIN) && (level <= TRACE_MAX)) 44 trace_level = level; 45 else 46 trace_level = TRACE_MAX; 47 } 48 49 int trace_get_level(void) 50 { 51 return trace_level; 52 } 53 54 static const char *trace_level_to_string(int level, bool level_ok) 55 { 56 static const char lvl_strs[][9] = { 57 "UNKNOWN:", "ERROR: ", "INFO: ", "DEBUG: ", 58 "FLOW: " }; 59 int l = 0; 60 61 if (!level_ok) 62 return "MESSAGE:"; 63 64 if ((level >= TRACE_MIN) && (level <= TRACE_MAX)) 65 l = level; 66 67 return lvl_strs[l]; 68 } 69 70 /* Format trace of user ta. Inline with kernel ta */ 71 void trace_printf(const char *function, int line, int level, bool level_ok, 72 const char *fmt, ...) 73 { 74 va_list ap; 75 char buf[MAX_PRINT_SIZE]; 76 size_t boffs = 0; 77 int res; 78 int thread_id; 79 80 if (level_ok && level > trace_level) 81 return; 82 83 res = snprintk(buf, sizeof(buf), "%s ", 84 trace_level_to_string(level, level_ok)); 85 if (res < 0) 86 return; 87 boffs += res; 88 89 if (level_ok && level < CFG_MSG_LONG_PREFIX_THRESHOLD) 90 thread_id = -1; 91 else 92 thread_id = trace_ext_get_thread_id(); 93 94 if (thread_id >= 0) { 95 res = snprintk(buf + boffs, sizeof(buf) - boffs, "[0x%x] ", 96 thread_id); 97 if (res < 0) 98 return; 99 boffs += res; 100 } 101 102 res = snprintk(buf + boffs, sizeof(buf) - boffs, "%s:", 103 trace_ext_prefix); 104 if (res < 0) 105 return; 106 boffs += res; 107 108 if (level_ok && level < CFG_MSG_LONG_PREFIX_THRESHOLD) 109 function = NULL; 110 111 if (function) { 112 res = snprintk(buf + boffs, sizeof(buf) - boffs, "%s:%d:", 113 function, line); 114 if (res < 0) 115 return; 116 boffs += res; 117 } 118 119 res = snprintk(buf + boffs, sizeof(buf) - boffs, " "); 120 if (res < 0) 121 return; 122 boffs += res; 123 124 va_start(ap, fmt); 125 res = vsnprintk(buf + boffs, sizeof(buf) - boffs, fmt, ap); 126 va_end(ap); 127 if (res > 0) 128 boffs += res; 129 130 if (boffs >= (sizeof(buf) - 1)) 131 boffs = sizeof(buf) - 2; 132 133 buf[boffs] = '\n'; 134 while (boffs && buf[boffs] == '\n') 135 boffs--; 136 boffs++; 137 buf[boffs + 1] = '\0'; 138 139 trace_ext_puts(buf); 140 } 141 142 #else 143 144 /* 145 * In case we have a zero or negative trace level when compiling optee_os, we 146 * have to add stubs to trace functions in case they are used with TA having a 147 * non-zero trace level 148 */ 149 150 void trace_set_level(int level __unused) 151 { 152 } 153 154 int trace_get_level(void) 155 { 156 return 0; 157 } 158 159 void trace_printf(const char *function __unused, int line __unused, 160 int level __unused, bool level_ok __unused, 161 const char *fmt __unused, ...) 162 { 163 } 164 165 #endif 166 167 #if (TRACE_LEVEL >= TRACE_DEBUG) 168 struct strbuf { 169 char buf[MAX_PRINT_SIZE]; 170 char *ptr; 171 }; 172 173 static int __printf(2, 3) append(struct strbuf *sbuf, const char *fmt, ...) 174 { 175 int left; 176 int len; 177 va_list ap; 178 179 if (sbuf->ptr == NULL) 180 sbuf->ptr = sbuf->buf; 181 left = sizeof(sbuf->buf) - (sbuf->ptr - sbuf->buf); 182 va_start(ap, fmt); 183 len = vsnprintk(sbuf->ptr, left, fmt, ap); 184 va_end(ap); 185 if (len < 0) { 186 /* Format error */ 187 return 0; 188 } 189 if (len >= left) { 190 /* Output was truncated */ 191 return 0; 192 } 193 sbuf->ptr += MIN(left, len); 194 return 1; 195 } 196 197 #define PRIxVA_WIDTH ((int)(sizeof(vaddr_t)*2)) 198 199 void dhex_dump(const char *function, int line, int level, 200 const void *buf, int len) 201 { 202 int i; 203 int ok; 204 struct strbuf sbuf; 205 char *in = (char *)buf; 206 207 if (level <= trace_level) { 208 sbuf.ptr = NULL; 209 for (i = 0; i < len; i++) { 210 if ((i % 16) == 0) { 211 ok = append(&sbuf, "%0*" PRIxVA " ", 212 PRIxVA_WIDTH, (vaddr_t)(in + i)); 213 if (!ok) 214 goto err; 215 } 216 ok = append(&sbuf, "%02x ", in[i]); 217 if (!ok) 218 goto err; 219 if ((i % 16) == 7) { 220 ok = append(&sbuf, " "); 221 if (!ok) 222 goto err; 223 } else if ((i % 16) == 15) { 224 trace_printf(function, line, level, true, "%s", 225 sbuf.buf); 226 sbuf.ptr = NULL; 227 } 228 } 229 if (sbuf.ptr) { 230 /* Buffer is not empty: flush it */ 231 trace_printf(function, line, level, true, "%s", 232 sbuf.buf); 233 234 } 235 } 236 return; 237 err: 238 DMSG("Hex dump error"); 239 } 240 #else 241 242 /* 243 * In case we have trace level less than debug when compiling optee_os, we have 244 * to add stubs to trace functions in case they are used with TA having a 245 * a higher trace level 246 */ 247 248 void dhex_dump(const char *function __unused, int line __unused, 249 int level __unused, 250 const void *buf __unused, int len __unused) 251 { 252 } 253 254 #endif 255