1 /* SPDX-License-Identifier: GPL-2.0-only */
4 * blatantly copied from linux/kernel/printk.c
7 #include <console/cbmem_console.h>
8 #include <console/console.h>
9 #include <console/streams.h>
10 #include <console/vtxprintf.h>
11 #include <smp/spinlock.h>
16 DECLARE_SPIN_LOCK(console_lock
)
18 #define TRACK_CONSOLE_TIME (!ENV_SMM && CONFIG(HAVE_MONOTONIC_TIMER))
20 static struct mono_time mt_start
, mt_stop
;
21 static long console_usecs
;
23 static void console_time_run(void)
25 if (TRACK_CONSOLE_TIME
&& boot_cpu())
26 timer_monotonic_get(&mt_start
);
29 static void console_time_stop(void)
31 if (TRACK_CONSOLE_TIME
&& boot_cpu()) {
32 timer_monotonic_get(&mt_stop
);
33 console_usecs
+= mono_time_diff_microseconds(&mt_start
, &mt_stop
);
37 void console_time_report(void)
39 if (!TRACK_CONSOLE_TIME
)
42 printk(BIOS_DEBUG
, "BS: " ENV_STRING
" times (exec / console): total (unknown) / %ld ms\n",
43 DIV_ROUND_CLOSEST(console_usecs
, USECS_PER_MSEC
));
46 long console_time_get_and_reset(void)
48 if (!TRACK_CONSOLE_TIME
)
51 long elapsed
= console_usecs
;
56 void do_putchar(unsigned char byte
)
59 console_tx_byte(byte
);
71 #define LOG_FAST(state) (HAS_ONLY_FAST_CONSOLES || ((state).speed == CONSOLE_LOG_FAST))
73 static void wrap_interactive_printf(const char *fmt
, ...)
77 vtxprintf(console_interactive_tx_byte
, fmt
, args
, NULL
);
81 static void line_start(union log_state state
)
83 if (state
.level
> BIOS_LOG_PREFIX_MAX_LEVEL
)
86 /* Stored consoles just get a single control char marker to save space. If we are in
87 LOG_FAST mode, just write the marker to CBMC and exit -- the rest of this function
88 implements the LOG_ALL case. */
89 unsigned char marker
= BIOS_LOG_LEVEL_TO_MARKER(state
.level
);
90 if (LOG_FAST(state
)) {
91 __cbmemc_tx_byte(marker
);
94 console_stored_tx_byte(marker
, NULL
);
96 /* Interactive consoles get a `[DEBUG] ` style readable prefix,
97 and potentially an escape sequence for highlighting. */
98 if (CONFIG(CONSOLE_USE_ANSI_ESCAPES
))
99 wrap_interactive_printf(BIOS_LOG_ESCAPE_PATTERN
, bios_log_escape
[state
.level
]);
100 if (CONFIG(CONSOLE_USE_LOGLEVEL_PREFIX
))
101 wrap_interactive_printf(BIOS_LOG_PREFIX_PATTERN
, bios_log_prefix
[state
.level
]);
104 static void line_end(union log_state state
)
106 if (CONFIG(CONSOLE_USE_ANSI_ESCAPES
) && !LOG_FAST(state
))
107 wrap_interactive_printf(BIOS_LOG_ESCAPE_RESET
);
110 static void wrap_putchar(unsigned char byte
, void *data
)
112 union log_state state
= { .as_ptr
= data
};
113 static bool line_started
= false;
117 line_started
= false;
118 } else if (!line_started
) {
124 __cbmemc_tx_byte(byte
);
126 console_tx_byte(byte
);
129 int vprintk(int msg_level
, const char *fmt
, va_list args
)
131 union log_state state
= { .level
= msg_level
};
134 if (CONFIG(SQUELCH_EARLY_SMP
) && ENV_ROMSTAGE_OR_BEFORE
&& !boot_cpu())
137 state
.speed
= console_log_level(msg_level
);
138 if (state
.speed
< CONSOLE_LOG_FAST
)
141 spin_lock(&console_lock
);
145 i
= vtxprintf(wrap_putchar
, fmt
, args
, state
.as_ptr
);
151 spin_unlock(&console_lock
);
156 int printk(int msg_level
, const char *fmt
, ...)
162 i
= vprintk(msg_level
, fmt
, args
);