| 1 | // SPDX-License-Identifier: GPL-3.0-or-later |
| 2 | |
| 3 | #include "mos/syslog/syslog.hpp" |
| 4 | |
| 5 | #include <mos/device/console.hpp> |
| 6 | #include <mos/lib/structures/list.hpp> |
| 7 | #include <mos/lib/sync/spinlock.hpp> |
| 8 | #include <mos/misc/cmdline.hpp> |
| 9 | #include <mos/misc/setup.hpp> |
| 10 | #include <mos/syslog/printk.hpp> |
| 11 | #include <mos_stdio.hpp> |
| 12 | #include <mos_string.hpp> |
| 13 | |
| 14 | Console *printk_console = NULL; |
| 15 | static bool printk_quiet = false; |
| 16 | |
| 17 | MOS_SETUP("printk_console" , printk_setup_console) |
| 18 | { |
| 19 | const auto kcon_name = arg; |
| 20 | if (kcon_name.empty()) |
| 21 | { |
| 22 | pr_warn("No console name given for printk" ); |
| 23 | return false; |
| 24 | } |
| 25 | |
| 26 | auto maybe_console = console_get(name: kcon_name); |
| 27 | if (maybe_console) |
| 28 | { |
| 29 | pr_emph("Selected console '%s' for future printk\n" , kcon_name); |
| 30 | printk_console = *maybe_console; |
| 31 | return true; |
| 32 | } |
| 33 | |
| 34 | maybe_console = console_get_by_prefix(name: kcon_name); |
| 35 | if (maybe_console) |
| 36 | { |
| 37 | printk_console = *maybe_console; |
| 38 | pr_emph("Selected console '%s' for future printk (prefix-based)\n" , printk_console->name().c_str()); |
| 39 | return true; |
| 40 | } |
| 41 | |
| 42 | mos_warn("No console found for printk based on given name or prefix '%s'" , kcon_name.data()); |
| 43 | printk_console = NULL; |
| 44 | return false; |
| 45 | } |
| 46 | |
| 47 | MOS_EARLY_SETUP("quiet" , printk_setup_quiet) |
| 48 | { |
| 49 | printk_quiet = cmdline_string_truthiness(arg, default_value: true); |
| 50 | return true; |
| 51 | } |
| 52 | |
| 53 | static inline void deduce_level_color(LogLevel loglevel, StandardColor *fg, StandardColor *bg) |
| 54 | { |
| 55 | *bg = Black; |
| 56 | switch (loglevel) |
| 57 | { |
| 58 | case LogLevel::INFO2: *fg = DarkGray; break; |
| 59 | case LogLevel::INFO: *fg = Gray; break; |
| 60 | case LogLevel::EMPH: *fg = Cyan; break; |
| 61 | case LogLevel::WARN: *fg = Brown; break; |
| 62 | case LogLevel::EMERG: *fg = Red; break; |
| 63 | case LogLevel::FATAL: *fg = White, *bg = Red; break; |
| 64 | default: break; // do not change the color |
| 65 | } |
| 66 | } |
| 67 | |
| 68 | void print_to_console(Console *con, LogLevel loglevel, const char *message, size_t len) |
| 69 | { |
| 70 | if (!con) |
| 71 | return; |
| 72 | |
| 73 | StandardColor fg = con->fg, bg = con->bg; |
| 74 | deduce_level_color(loglevel, fg: &fg, bg: &bg); |
| 75 | con->WriteColored(data: message, size: len, fg, bg); |
| 76 | } |
| 77 | |
| 78 | void lvprintk(LogLevel loglevel, const char *fmt, va_list args) |
| 79 | { |
| 80 | // only print warnings and errors if quiet mode is enabled |
| 81 | if (printk_quiet && loglevel < LogLevel::WARN) |
| 82 | return; |
| 83 | |
| 84 | char message[MOS_PRINTK_BUFFER_SIZE]; |
| 85 | const int len = vsnprintf(buf: message, MOS_PRINTK_BUFFER_SIZE, format: fmt, args); |
| 86 | |
| 87 | if (unlikely(!printk_console)) |
| 88 | printk_console = consoles.front(); |
| 89 | print_to_console(con: printk_console, loglevel, message, len); |
| 90 | } |
| 91 | |
| 92 | bool printk_unquiet(void) |
| 93 | { |
| 94 | bool was_quiet = printk_quiet; |
| 95 | printk_quiet = false; |
| 96 | return was_quiet; |
| 97 | } |
| 98 | |
| 99 | void printk_set_quiet(bool quiet) |
| 100 | { |
| 101 | printk_quiet = quiet; |
| 102 | } |
| 103 | |
| 104 | void lprintk(LogLevel loglevel, const char *format, ...) |
| 105 | { |
| 106 | va_list args; |
| 107 | va_start(args, format); |
| 108 | lvprintk(loglevel, fmt: format, args); |
| 109 | va_end(args); |
| 110 | } |
| 111 | |
| 112 | void printk(const char *format, ...) |
| 113 | { |
| 114 | va_list args; |
| 115 | va_start(args, format); |
| 116 | lvprintk(loglevel: LogLevel::INFO, fmt: format, args); |
| 117 | va_end(args); |
| 118 | } |
| 119 | |