spl: Add a separate silence option for SPL
[platform/kernel/u-boot.git] / common / log.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Logging support
4  *
5  * Copyright (c) 2017 Google, Inc
6  * Written by Simon Glass <sjg@chromium.org>
7  */
8
9 #include <common.h>
10 #include <display_options.h>
11 #include <log.h>
12 #include <malloc.h>
13 #include <asm/global_data.h>
14 #include <dm/uclass.h>
15
16 DECLARE_GLOBAL_DATA_PTR;
17
18 static const char *const log_cat_name[] = {
19         "none",
20         "arch",
21         "board",
22         "core",
23         "driver-model",
24         "device-tree",
25         "efi",
26         "alloc",
27         "sandbox",
28         "bloblist",
29         "devres",
30         "acpi",
31         "boot",
32         "event",
33 };
34
35 _Static_assert(ARRAY_SIZE(log_cat_name) == LOGC_COUNT - LOGC_NONE,
36                "log_cat_name size");
37
38 static const char *const log_level_name[] = {
39         "EMERG",
40         "ALERT",
41         "CRIT",
42         "ERR",
43         "WARNING",
44         "NOTICE",
45         "INFO",
46         "DEBUG",
47         "CONTENT",
48         "IO",
49 };
50
51 _Static_assert(ARRAY_SIZE(log_level_name) == LOGL_COUNT, "log_level_name size");
52
53 /* All error responses MUST begin with '<' */
54 const char *log_get_cat_name(enum log_category_t cat)
55 {
56         const char *name;
57
58         if (cat < 0 || cat >= LOGC_COUNT)
59                 return "<invalid>";
60         if (cat >= LOGC_NONE)
61                 return log_cat_name[cat - LOGC_NONE];
62
63 #if CONFIG_IS_ENABLED(DM)
64         name = uclass_get_name((enum uclass_id)cat);
65 #else
66         name = NULL;
67 #endif
68
69         return name ? name : "<missing>";
70 }
71
72 enum log_category_t log_get_cat_by_name(const char *name)
73 {
74         enum uclass_id id;
75         int i;
76
77         for (i = LOGC_NONE; i < LOGC_COUNT; i++)
78                 if (!strcmp(name, log_cat_name[i - LOGC_NONE]))
79                         return i;
80         id = uclass_get_by_name(name);
81         if (id != UCLASS_INVALID)
82                 return (enum log_category_t)id;
83
84         return LOGC_NONE;
85 }
86
87 const char *log_get_level_name(enum log_level_t level)
88 {
89         if (level >= LOGL_COUNT)
90                 return "INVALID";
91         return log_level_name[level];
92 }
93
94 enum log_level_t log_get_level_by_name(const char *name)
95 {
96         int i;
97
98         for (i = 0; i < LOGL_COUNT; i++) {
99                 if (!strcasecmp(log_level_name[i], name))
100                         return i;
101         }
102
103         return LOGL_NONE;
104 }
105
106 struct log_device *log_device_find_by_name(const char *drv_name)
107 {
108         struct log_device *ldev;
109
110         list_for_each_entry(ldev, &gd->log_head, sibling_node) {
111                 if (!strcmp(drv_name, ldev->drv->name))
112                         return ldev;
113         }
114
115         return NULL;
116 }
117
118 bool log_has_cat(enum log_category_t cat_list[], enum log_category_t cat)
119 {
120         int i;
121
122         for (i = 0; i < LOGF_MAX_CATEGORIES && cat_list[i] != LOGC_END; i++) {
123                 if (cat_list[i] == cat)
124                         return true;
125         }
126
127         return false;
128 }
129
130 bool log_has_file(const char *file_list, const char *file)
131 {
132         int file_len = strlen(file);
133         const char *s, *p;
134         int substr_len;
135
136         for (s = file_list; *s; s = p + (*p != '\0')) {
137                 p = strchrnul(s, ',');
138                 substr_len = p - s;
139                 if (file_len >= substr_len &&
140                     !strncmp(file + file_len - substr_len, s, substr_len))
141                         return true;
142         }
143
144         return false;
145 }
146
147 /**
148  * log_passes_filters() - check if a log record passes the filters for a device
149  *
150  * @ldev: Log device to check
151  * @rec: Log record to check
152  * Return: true if @rec is not blocked by the filters in @ldev, false if it is
153  */
154 static bool log_passes_filters(struct log_device *ldev, struct log_rec *rec)
155 {
156         struct log_filter *filt;
157
158         if (rec->flags & LOGRECF_FORCE_DEBUG)
159                 return true;
160
161         /* If there are no filters, filter on the default log level */
162         if (list_empty(&ldev->filter_head)) {
163                 if (rec->level > gd->default_log_level)
164                         return false;
165                 return true;
166         }
167
168         list_for_each_entry(filt, &ldev->filter_head, sibling_node) {
169                 if (filt->flags & LOGFF_LEVEL_MIN) {
170                         if (rec->level < filt->level)
171                                 continue;
172                 } else if (rec->level > filt->level) {
173                         continue;
174                 }
175
176                 if ((filt->flags & LOGFF_HAS_CAT) &&
177                     !log_has_cat(filt->cat_list, rec->cat))
178                         continue;
179
180                 if (filt->file_list &&
181                     !log_has_file(filt->file_list, rec->file))
182                         continue;
183
184                 if (filt->flags & LOGFF_DENY)
185                         return false;
186                 else
187                         return true;
188         }
189
190         return false;
191 }
192
193 /**
194  * log_dispatch() - Send a log record to all log devices for processing
195  *
196  * The log record is sent to each log device in turn, skipping those which have
197  * filters which block the record.
198  *
199  * All log messages created while processing log record @rec are ignored.
200  *
201  * @rec:        log record to dispatch
202  * Return:      0 msg sent, 1 msg not sent while already dispatching another msg
203  */
204 static int log_dispatch(struct log_rec *rec, const char *fmt, va_list args)
205 {
206         struct log_device *ldev;
207         char buf[CONFIG_SYS_CBSIZE];
208
209         /*
210          * When a log driver writes messages (e.g. via the network stack) this
211          * may result in further generated messages. We cannot process them here
212          * as this might result in infinite recursion.
213          */
214         if (gd->processing_msg)
215                 return 1;
216
217         /* Emit message */
218         gd->processing_msg = true;
219         list_for_each_entry(ldev, &gd->log_head, sibling_node) {
220                 if ((ldev->flags & LOGDF_ENABLE) &&
221                     log_passes_filters(ldev, rec)) {
222                         if (!rec->msg) {
223                                 int len;
224
225                                 len = vsnprintf(buf, sizeof(buf), fmt, args);
226                                 rec->msg = buf;
227                                 gd->log_cont = len && buf[len - 1] != '\n';
228                         }
229                         ldev->drv->emit(ldev, rec);
230                 }
231         }
232         gd->processing_msg = false;
233         return 0;
234 }
235
236 int _log(enum log_category_t cat, enum log_level_t level, const char *file,
237          int line, const char *func, const char *fmt, ...)
238 {
239         struct log_rec rec;
240         va_list args;
241
242         if (!gd)
243                 return -ENOSYS;
244
245         /* Check for message continuation */
246         if (cat == LOGC_CONT)
247                 cat = gd->logc_prev;
248         if (level == LOGL_CONT)
249                 level = gd->logl_prev;
250
251         rec.cat = cat;
252         rec.level = level & LOGL_LEVEL_MASK;
253         rec.flags = 0;
254         if (level & LOGL_FORCE_DEBUG)
255                 rec.flags |= LOGRECF_FORCE_DEBUG;
256         if (gd->log_cont)
257                 rec.flags |= LOGRECF_CONT;
258         rec.file = file;
259         rec.line = line;
260         rec.func = func;
261         rec.msg = NULL;
262
263         if (!(gd->flags & GD_FLG_LOG_READY)) {
264                 gd->log_drop_count++;
265
266                 /* display dropped traces with console puts and DEBUG_UART */
267                 if (rec.level <= CONFIG_LOG_DEFAULT_LEVEL ||
268                     rec.flags & LOGRECF_FORCE_DEBUG) {
269                         char buf[CONFIG_SYS_CBSIZE];
270
271                         va_start(args, fmt);
272                         vsnprintf(buf, sizeof(buf), fmt, args);
273                         puts(buf);
274                         va_end(args);
275                 }
276
277                 return -ENOSYS;
278         }
279         va_start(args, fmt);
280         if (!log_dispatch(&rec, fmt, args)) {
281                 gd->logc_prev = cat;
282                 gd->logl_prev = level;
283         }
284         va_end(args);
285
286         return 0;
287 }
288
289 #define MAX_LINE_LENGTH_BYTES           64
290 #define DEFAULT_LINE_LENGTH_BYTES       16
291
292 int _log_buffer(enum log_category_t cat, enum log_level_t level,
293                 const char *file, int line, const char *func, ulong addr,
294                 const void *data, uint width, uint count, uint linelen)
295 {
296         if (linelen * width > MAX_LINE_LENGTH_BYTES)
297                 linelen = MAX_LINE_LENGTH_BYTES / width;
298         if (linelen < 1)
299                 linelen = DEFAULT_LINE_LENGTH_BYTES / width;
300
301         while (count) {
302                 uint thislinelen;
303                 char buf[HEXDUMP_MAX_BUF_LENGTH(width * linelen)];
304
305                 thislinelen = hexdump_line(addr, data, width, count, linelen,
306                                            buf, sizeof(buf));
307                 assert(thislinelen >= 0);
308                 _log(cat, level, file, line, func, "%s\n", buf);
309
310                 /* update references */
311                 data += thislinelen * width;
312                 addr += thislinelen * width;
313                 count -= thislinelen;
314         }
315
316         return 0;
317 }
318
319 int log_add_filter_flags(const char *drv_name, enum log_category_t cat_list[],
320                          enum log_level_t level, const char *file_list,
321                          int flags)
322 {
323         struct log_filter *filt;
324         struct log_device *ldev;
325         int ret;
326         int i;
327
328         ldev = log_device_find_by_name(drv_name);
329         if (!ldev)
330                 return -ENOENT;
331         filt = calloc(1, sizeof(*filt));
332         if (!filt)
333                 return -ENOMEM;
334
335         filt->flags = flags;
336         if (cat_list) {
337                 filt->flags |= LOGFF_HAS_CAT;
338                 for (i = 0; ; i++) {
339                         if (i == ARRAY_SIZE(filt->cat_list)) {
340                                 ret = -ENOSPC;
341                                 goto err;
342                         }
343                         filt->cat_list[i] = cat_list[i];
344                         if (cat_list[i] == LOGC_END)
345                                 break;
346                 }
347         }
348         filt->level = level;
349         if (file_list) {
350                 filt->file_list = strdup(file_list);
351                 if (!filt->file_list) {
352                         ret = -ENOMEM;
353                         goto err;
354                 }
355         }
356         filt->filter_num = ldev->next_filter_num++;
357         /* Add deny filters to the beginning of the list */
358         if (flags & LOGFF_DENY)
359                 list_add(&filt->sibling_node, &ldev->filter_head);
360         else
361                 list_add_tail(&filt->sibling_node, &ldev->filter_head);
362
363         return filt->filter_num;
364
365 err:
366         free(filt);
367         return ret;
368 }
369
370 int log_remove_filter(const char *drv_name, int filter_num)
371 {
372         struct log_filter *filt;
373         struct log_device *ldev;
374
375         ldev = log_device_find_by_name(drv_name);
376         if (!ldev)
377                 return -ENOENT;
378
379         list_for_each_entry(filt, &ldev->filter_head, sibling_node) {
380                 if (filt->filter_num == filter_num) {
381                         list_del(&filt->sibling_node);
382                         free(filt);
383
384                         return 0;
385                 }
386         }
387
388         return -ENOENT;
389 }
390
391 /**
392  * log_find_device_by_drv() - Find a device by its driver
393  *
394  * @drv: Log driver
395  * Return: Device associated with that driver, or NULL if not found
396  */
397 static struct log_device *log_find_device_by_drv(struct log_driver *drv)
398 {
399         struct log_device *ldev;
400
401         list_for_each_entry(ldev, &gd->log_head, sibling_node) {
402                 if (ldev->drv == drv)
403                         return ldev;
404         }
405         /*
406          * It is quite hard to pass an invalid driver since passing an unknown
407          * LOG_GET_DRIVER(xxx) would normally produce a compilation error. But
408          * it is possible to pass NULL, for example, so this
409          */
410
411         return NULL;
412 }
413
414 int log_device_set_enable(struct log_driver *drv, bool enable)
415 {
416         struct log_device *ldev;
417
418         ldev = log_find_device_by_drv(drv);
419         if (!ldev)
420                 return -ENOENT;
421         if (enable)
422                 ldev->flags |= LOGDF_ENABLE;
423         else
424                 ldev->flags &= ~LOGDF_ENABLE;
425
426         return 0;
427 }
428
429 int log_init(void)
430 {
431         struct log_driver *drv = ll_entry_start(struct log_driver, log_driver);
432         const int count = ll_entry_count(struct log_driver, log_driver);
433         struct log_driver *end = drv + count;
434
435         /*
436          * We cannot add runtime data to the driver since it is likely stored
437          * in rodata. Instead, set up a 'device' corresponding to each driver.
438          * We only support having a single device.
439          */
440         INIT_LIST_HEAD((struct list_head *)&gd->log_head);
441         while (drv < end) {
442                 struct log_device *ldev;
443
444                 ldev = calloc(1, sizeof(*ldev));
445                 if (!ldev) {
446                         debug("%s: Cannot allocate memory\n", __func__);
447                         return -ENOMEM;
448                 }
449                 INIT_LIST_HEAD(&ldev->filter_head);
450                 ldev->drv = drv;
451                 ldev->flags = drv->flags;
452                 list_add_tail(&ldev->sibling_node,
453                               (struct list_head *)&gd->log_head);
454                 drv++;
455         }
456         gd->flags |= GD_FLG_LOG_READY;
457         if (!gd->default_log_level)
458                 gd->default_log_level = CONFIG_LOG_DEFAULT_LEVEL;
459         gd->log_fmt = log_get_default_format();
460         gd->logc_prev = LOGC_NONE;
461         gd->logl_prev = LOGL_INFO;
462
463         return 0;
464 }