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 buf[boffs + 1] = '\0'; 135 136 trace_ext_puts(buf); 137 } 138 139 #else 140 141 /* 142 * In case we have a zero or negative trace level when compiling optee_os, we 143 * have to add stubs to trace functions in case they are used with TA having a 144 * non-zero trace level 145 */ 146 147 void trace_set_level(int level __unused) 148 { 149 } 150 151 int trace_get_level(void) 152 { 153 return 0; 154 } 155 156 void trace_printf(const char *function __unused, int line __unused, 157 int level __unused, bool level_ok __unused, 158 const char *fmt __unused, ...) 159 { 160 } 161 162 #endif 163 164 #if (TRACE_LEVEL >= TRACE_DEBUG) 165 struct strbuf { 166 char buf[MAX_PRINT_SIZE]; 167 char *ptr; 168 }; 169 170 static int __printf(2, 3) append(struct strbuf *sbuf, const char *fmt, ...) 171 { 172 int left; 173 int len; 174 va_list ap; 175 176 if (sbuf->ptr == NULL) 177 sbuf->ptr = sbuf->buf; 178 left = sizeof(sbuf->buf) - (sbuf->ptr - sbuf->buf); 179 va_start(ap, fmt); 180 len = vsnprintk(sbuf->ptr, left, fmt, ap); 181 va_end(ap); 182 if (len < 0) { 183 /* Format error */ 184 return 0; 185 } 186 if (len >= left) { 187 /* Output was truncated */ 188 return 0; 189 } 190 sbuf->ptr += MIN(left, len); 191 return 1; 192 } 193 194 #define PRIxVA_WIDTH ((int)(sizeof(vaddr_t)*2)) 195 196 void dhex_dump(const char *function, int line, int level, 197 const void *buf, int len) 198 { 199 int i; 200 int ok; 201 struct strbuf sbuf; 202 char *in = (char *)buf; 203 204 if (level <= trace_level) { 205 sbuf.ptr = NULL; 206 for (i = 0; i < len; i++) { 207 if ((i % 16) == 0) { 208 ok = append(&sbuf, "%0*" PRIxVA " ", 209 PRIxVA_WIDTH, (vaddr_t)(in + i)); 210 if (!ok) 211 goto err; 212 } 213 ok = append(&sbuf, "%02x ", in[i]); 214 if (!ok) 215 goto err; 216 if ((i % 16) == 7) { 217 ok = append(&sbuf, " "); 218 if (!ok) 219 goto err; 220 } else if ((i % 16) == 15) { 221 trace_printf(function, line, level, true, "%s", 222 sbuf.buf); 223 sbuf.ptr = NULL; 224 } 225 } 226 if (sbuf.ptr) { 227 /* Buffer is not empty: flush it */ 228 trace_printf(function, line, level, true, "%s", 229 sbuf.buf); 230 231 } 232 } 233 return; 234 err: 235 DMSG("Hex dump error"); 236 } 237 #else 238 239 /* 240 * In case we have trace level less than debug when compiling optee_os, we have 241 * to add stubs to trace functions in case they are used with TA having a 242 * a higher trace level 243 */ 244 245 void dhex_dump(const char *function __unused, int line __unused, 246 int level __unused, 247 const void *buf __unused, int len __unused) 248 { 249 } 250 251 #endif 252