blob: 1ce2fad55f3242aa1e6fc55f5e03b47c5d8838d6 [file] [log] [blame]
Angel Ponsb706ab32020-04-02 23:48:09 +02001/* SPDX-License-Identifier: GPL-2.0-only */
Angel Ponsb706ab32020-04-02 23:48:09 +02002
Eric Biederman8ca8d762003-04-22 19:02:15 +00003/*
Damien Roth4e7e9872016-01-16 18:59:51 -07004 * blatantly copied from linux/kernel/printk.c
Eric Biederman8ca8d762003-04-22 19:02:15 +00005 */
Eric Biederman8ca8d762003-04-22 19:02:15 +00006
Kyösti Mälkkie613d702019-02-12 14:16:21 +02007#include <console/cbmem_console.h>
Eric Biederman8ca8d762003-04-22 19:02:15 +00008#include <console/console.h>
Kyösti Mälkki40760722014-02-27 19:30:18 +02009#include <console/streams.h>
Edward O'Callaghan0ddb8262014-06-17 18:37:08 +100010#include <console/vtxprintf.h>
11#include <smp/spinlock.h>
12#include <smp/node.h>
Kyösti Mälkki45ddb432019-11-02 14:12:18 +020013#include <timer.h>
Eric Biederman8ca8d762003-04-22 19:02:15 +000014
Myles Watson2e672732009-11-12 16:38:03 +000015DECLARE_SPIN_LOCK(console_lock)
Eric Biederman8ca8d762003-04-22 19:02:15 +000016
Kyösti Mälkki05fe16c2019-12-01 08:38:11 +020017#define TRACK_CONSOLE_TIME (!ENV_SMM && CONFIG(HAVE_MONOTONIC_TIMER))
Kyösti Mälkki45ddb432019-11-02 14:12:18 +020018
19static struct mono_time mt_start, mt_stop;
20static long console_usecs;
21
22static void console_time_run(void)
23{
Kyösti Mälkki05fe16c2019-12-01 08:38:11 +020024 if (TRACK_CONSOLE_TIME && boot_cpu())
Kyösti Mälkki45ddb432019-11-02 14:12:18 +020025 timer_monotonic_get(&mt_start);
26}
27
28static void console_time_stop(void)
29{
Kyösti Mälkki05fe16c2019-12-01 08:38:11 +020030 if (TRACK_CONSOLE_TIME && boot_cpu()) {
Kyösti Mälkki45ddb432019-11-02 14:12:18 +020031 timer_monotonic_get(&mt_stop);
32 console_usecs += mono_time_diff_microseconds(&mt_start, &mt_stop);
33 }
34}
35
36void console_time_report(void)
37{
38 if (!TRACK_CONSOLE_TIME)
39 return;
40
Kyösti Mälkki94694a82019-11-02 18:14:31 +020041 printk(BIOS_DEBUG, "BS: " ENV_STRING " times (exec / console): total (unknown) / %ld ms\n",
Kyösti Mälkki45ddb432019-11-02 14:12:18 +020042 DIV_ROUND_CLOSEST(console_usecs, USECS_PER_MSEC));
43}
44
45long console_time_get_and_reset(void)
46{
47 if (!TRACK_CONSOLE_TIME)
48 return 0;
49
50 long elapsed = console_usecs;
51 console_usecs = 0;
52 return elapsed;
53}
54
Kyösti Mälkki657e0be2014-02-04 19:03:57 +020055void do_putchar(unsigned char byte)
56{
Kyösti Mälkki45ddb432019-11-02 14:12:18 +020057 console_time_run();
Kyösti Mälkki657e0be2014-02-04 19:03:57 +020058 console_tx_byte(byte);
Kyösti Mälkki45ddb432019-11-02 14:12:18 +020059 console_time_stop();
Kyösti Mälkki657e0be2014-02-04 19:03:57 +020060}
61
Julius Wernerb6cf6422022-02-02 17:21:02 -080062union log_state {
63 void *as_ptr;
64 struct {
65 uint8_t level;
66 uint8_t speed;
67 };
68};
69
Mario Scheithauerf6056112022-02-22 09:46:33 +010070#define LOG_FAST(state) (HAS_ONLY_FAST_CONSOLES || ((state).speed == CONSOLE_LOG_FAST))
Julius Werner266041f2022-02-03 17:25:44 -080071
Julius Werner7cd8ba62022-01-21 15:15:29 -080072static void wrap_interactive_printf(const char *fmt, ...)
73{
74 va_list args;
75 va_start(args, fmt);
76 vtxprintf(console_interactive_tx_byte, fmt, args, NULL);
Julius Wernerababf012022-02-08 16:37:41 -080077 va_end(args);
Julius Werner7cd8ba62022-01-21 15:15:29 -080078}
79
80static void line_start(union log_state state)
81{
82 if (state.level > BIOS_LOG_PREFIX_MAX_LEVEL)
83 return;
Julius Werner984d03c2022-01-21 15:33:47 -080084
85 /* Stored consoles just get a single control char marker to save space. If we are in
86 LOG_FAST mode, just write the marker to CBMC and exit -- the rest of this function
87 implements the LOG_ALL case. */
88 unsigned char marker = BIOS_LOG_LEVEL_TO_MARKER(state.level);
Julius Werner266041f2022-02-03 17:25:44 -080089 if (LOG_FAST(state)) {
Julius Werner984d03c2022-01-21 15:33:47 -080090 __cbmemc_tx_byte(marker);
Julius Werner7cd8ba62022-01-21 15:15:29 -080091 return;
Julius Werner984d03c2022-01-21 15:33:47 -080092 }
93 console_stored_tx_byte(marker, NULL);
Julius Werner7cd8ba62022-01-21 15:15:29 -080094
Julius Wernera120e0d2022-01-21 15:24:12 -080095 /* Interactive consoles get a `[DEBUG] ` style readable prefix,
96 and potentially an escape sequence for highlighting. */
97 if (CONFIG(CONSOLE_USE_ANSI_ESCAPES))
98 wrap_interactive_printf(BIOS_LOG_ESCAPE_PATTERN, bios_log_escape[state.level]);
Igor Bagnuckif0d65212022-03-03 11:41:57 +010099 if (CONFIG(CONSOLE_USE_LOGLEVEL_PREFIX))
100 wrap_interactive_printf(BIOS_LOG_PREFIX_PATTERN, bios_log_prefix[state.level]);
Julius Werner7cd8ba62022-01-21 15:15:29 -0800101}
102
Julius Wernera120e0d2022-01-21 15:24:12 -0800103static void line_end(union log_state state)
104{
Julius Werner266041f2022-02-03 17:25:44 -0800105 if (CONFIG(CONSOLE_USE_ANSI_ESCAPES) && !LOG_FAST(state))
Julius Wernera120e0d2022-01-21 15:24:12 -0800106 wrap_interactive_printf(BIOS_LOG_ESCAPE_RESET);
107}
108
Kyösti Mälkki77f43e92014-02-04 19:50:07 +0200109static void wrap_putchar(unsigned char byte, void *data)
Kyösti Mälkkib04e0ff2014-02-04 14:28:17 +0200110{
Julius Wernerb6cf6422022-02-02 17:21:02 -0800111 union log_state state = { .as_ptr = data };
Julius Werner7cd8ba62022-01-21 15:15:29 -0800112 static bool line_started = false;
113
114 if (byte == '\n') {
Julius Wernera120e0d2022-01-21 15:24:12 -0800115 line_end(state);
Julius Werner7cd8ba62022-01-21 15:15:29 -0800116 line_started = false;
117 } else if (!line_started) {
118 line_start(state);
119 line_started = true;
120 }
Kyösti Mälkkie613d702019-02-12 14:16:21 +0200121
Julius Werner266041f2022-02-03 17:25:44 -0800122 if (LOG_FAST(state))
Julius Wernerb6cf6422022-02-02 17:21:02 -0800123 __cbmemc_tx_byte(byte);
124 else
125 console_tx_byte(byte);
Kyösti Mälkkib04e0ff2014-02-04 14:28:17 +0200126}
127
Nico Huber7cc14ac2021-03-27 20:03:02 +0100128int vprintk(int msg_level, const char *fmt, va_list args)
Eric Biederman8ca8d762003-04-22 19:02:15 +0000129{
Julius Wernerb6cf6422022-02-02 17:21:02 -0800130 union log_state state = { .level = msg_level };
131 int i;
Eric Biederman8ca8d762003-04-22 19:02:15 +0000132
Kyösti Mälkki21160a72019-08-17 17:29:36 +0300133 if (CONFIG(SQUELCH_EARLY_SMP) && ENV_ROMSTAGE_OR_BEFORE && !boot_cpu())
Eric Biederman8ca8d762003-04-22 19:02:15 +0000134 return 0;
Eric Biederman8ca8d762003-04-22 19:02:15 +0000135
Julius Wernerb6cf6422022-02-02 17:21:02 -0800136 state.speed = console_log_level(msg_level);
137 if (state.speed < CONSOLE_LOG_FAST)
Kyösti Mälkkib2d25962014-01-27 15:09:13 +0200138 return 0;
Kyösti Mälkkib2d25962014-01-27 15:09:13 +0200139
Eric Biederman8ca8d762003-04-22 19:02:15 +0000140 spin_lock(&console_lock);
141
Kyösti Mälkki45ddb432019-11-02 14:12:18 +0200142 console_time_run();
143
Julius Wernerb6cf6422022-02-02 17:21:02 -0800144 i = vtxprintf(wrap_putchar, fmt, args, state.as_ptr);
Julius Werner266041f2022-02-03 17:25:44 -0800145 if (LOG_FAST(state))
Kyösti Mälkkie613d702019-02-12 14:16:21 +0200146 console_tx_flush();
Eric Biederman8ca8d762003-04-22 19:02:15 +0000147
Kyösti Mälkki45ddb432019-11-02 14:12:18 +0200148 console_time_stop();
149
Eric Biederman8ca8d762003-04-22 19:02:15 +0000150 spin_unlock(&console_lock);
Eric Biederman8ca8d762003-04-22 19:02:15 +0000151
152 return i;
153}
Kyösti Mälkkib3356bb2014-03-06 16:55:05 +0200154
Nico Huber7cc14ac2021-03-27 20:03:02 +0100155int printk(int msg_level, const char *fmt, ...)
Kyösti Mälkkib3356bb2014-03-06 16:55:05 +0200156{
Kyösti Mälkki7132f252019-02-14 23:08:29 +0200157 va_list args;
158 int i;
159
160 va_start(args, fmt);
Nico Huber7cc14ac2021-03-27 20:03:02 +0100161 i = vprintk(msg_level, fmt, args);
Kyösti Mälkki7132f252019-02-14 23:08:29 +0200162 va_end(args);
163
164 return i;
Kyösti Mälkkib3356bb2014-03-06 16:55:05 +0200165}