blob: 0c5609573224f099d0c045f6f3679cd22075c615 [file] [log] [blame]
Angel Pons118a9c72020-04-02 23:48:34 +02001/* SPDX-License-Identifier: GPL-2.0-only */
Vadim Bendebury32da8be2011-09-29 17:27:15 -07002
Kyösti Mälkki1d7541f2014-02-17 21:34:42 +02003#include <console/cbmem_console.h>
Raul E Rangelbf993112022-01-11 12:48:50 -07004#include <console/console.h>
Vadim Bendebury6e20e2f2015-04-10 18:04:04 -07005#include <console/uart.h>
Vadim Bendebury32da8be2011-09-29 17:27:15 -07006#include <cbmem.h>
Julius Wernerec5e5e02014-08-20 15:29:56 -07007#include <symbols.h>
Raul E Rangelbf993112022-01-11 12:48:50 -07008#include <types.h>
Vadim Bendebury32da8be2011-09-29 17:27:15 -07009
10/*
11 * Structure describing console buffer. It is overlaid on a flat memory area,
Julius Wernerd67c6872017-02-02 17:32:00 -080012 * with body covering the extent of the memory. Once the buffer is full,
13 * output will wrap back around to the start of the buffer. The high bit of the
14 * cursor field gets set to indicate that this happened. If the underlying
15 * storage allows this, the buffer will persist across multiple boots and append
16 * to the previous log.
Julius Wernera915cea2017-04-24 17:08:06 -070017 *
18 * NOTE: These are known implementations accessing this console that need to be
19 * updated in case of structure/API changes:
20 *
21 * cbmem: [coreboot]/src/util/cbmem/cbmem.c
22 * libpayload: [coreboot]/payloads/libpayload/drivers/cbmem_console.c
23 * coreinfo: [coreboot]/payloads/coreinfo/bootlog_module.c
24 * Linux: drivers/firmware/google/memconsole-coreboot.c
25 * SeaBIOS: src/firmware/coreboot.c
26 * GRUB: grub-core/term/i386/coreboot/cbmemc.c
Vadim Bendebury32da8be2011-09-29 17:27:15 -070027 */
28struct cbmem_console {
Julius Wernerd09dc6b2017-02-03 12:45:21 -080029 u32 size;
30 u32 cursor;
31 u8 body[0];
Stefan Reinauer6a001132017-07-13 02:20:27 +020032} __packed;
Vadim Bendebury32da8be2011-09-29 17:27:15 -070033
Julius Wernerd67c6872017-02-02 17:32:00 -080034#define MAX_SIZE (1 << 28) /* can't be changed without breaking readers! */
35#define CURSOR_MASK (MAX_SIZE - 1) /* bits 31-28 are reserved for flags */
Ryan Salsamendifce582f2017-06-09 19:47:57 -070036#define OVERFLOW (1UL << 31) /* set if in ring-buffer mode */
Julius Wernerd67c6872017-02-02 17:32:00 -080037_Static_assert(CONFIG_CONSOLE_CBMEM_BUFFER_SIZE <= MAX_SIZE,
38 "cbmem_console format cannot support buffers larger than 256MB!");
Aaron Durbin2ad6bd22013-05-10 00:45:37 -050039
Patrick Georgia8582c42019-11-30 10:49:17 +010040static struct cbmem_console *current_console;
Kyösti Mälkki8659e402014-12-21 08:55:47 +020041
Raul E Rangelbf993112022-01-11 12:48:50 -070042static bool console_paused;
43
Vadim Bendebury32da8be2011-09-29 17:27:15 -070044/*
45 * While running from ROM, before DRAM is initialized, some area in cache as
Elyes HAOUAS91e0e3c2016-07-30 15:51:13 +020046 * RAM space is used for the console buffer storage. The size and location of
Julius Wernerec5e5e02014-08-20 15:29:56 -070047 * the area are defined by the linker script with _(e)preram_cbmem_console.
Kyösti Mälkkie3acc8f2019-09-13 10:49:20 +030048 *
Kyösti Mälkki513a1a82018-06-03 12:29:50 +030049 * When running from RAM, some console output is generated before CBMEM is
Vadim Bendebury32da8be2011-09-29 17:27:15 -070050 * reinitialized. This static buffer is used to store that output temporarily,
51 * to be concatenated with the CBMEM console buffer contents accumulated
52 * during the ROM stage, once CBMEM becomes available at RAM stage.
53 */
Stefan Reinauer19d06b22013-09-09 11:22:18 -070054
Stefan Reinauer19d06b22013-09-09 11:22:18 -070055#define STATIC_CONSOLE_SIZE 1024
Stefan Reinauer19d06b22013-09-09 11:22:18 -070056static u8 static_console[STATIC_CONSOLE_SIZE];
Vadim Bendebury32da8be2011-09-29 17:27:15 -070057
Julius Wernerd67c6872017-02-02 17:32:00 -080058static int buffer_valid(struct cbmem_console *cbm_cons_p, u32 total_space)
59{
60 return (cbm_cons_p->cursor & CURSOR_MASK) < cbm_cons_p->size &&
61 cbm_cons_p->size <= MAX_SIZE &&
62 cbm_cons_p->size == total_space - sizeof(struct cbmem_console);
63}
64
65static void init_console_ptr(void *storage, u32 total_space)
Aaron Durbin2ad6bd22013-05-10 00:45:37 -050066{
67 struct cbmem_console *cbm_cons_p = storage;
68
Julius Wernerd67c6872017-02-02 17:32:00 -080069 if (!cbm_cons_p || total_space <= sizeof(struct cbmem_console)) {
Patrick Georgia8582c42019-11-30 10:49:17 +010070 current_console = NULL;
Kyösti Mälkki8659e402014-12-21 08:55:47 +020071 return;
72 }
73
Julius Wernerd67c6872017-02-02 17:32:00 -080074 if (!buffer_valid(cbm_cons_p, total_space)) {
Julius Wernerd09dc6b2017-02-03 12:45:21 -080075 cbm_cons_p->size = total_space - sizeof(struct cbmem_console);
76 cbm_cons_p->cursor = 0;
Kyösti Mälkki8659e402014-12-21 08:55:47 +020077 }
Kyösti Mälkki8659e402014-12-21 08:55:47 +020078
Patrick Georgia8582c42019-11-30 10:49:17 +010079 current_console = cbm_cons_p;
Aaron Durbin2ad6bd22013-05-10 00:45:37 -050080}
81
82void cbmemc_init(void)
83{
Kyösti Mälkkie3acc8f2019-09-13 10:49:20 +030084 if (ENV_ROMSTAGE_OR_BEFORE) {
85 /* Pre-RAM environments use special buffer placed by linker script. */
86 init_console_ptr(_preram_cbmem_console, REGION_SIZE(preram_cbmem_console));
87 } else {
88 /* Post-RAM uses static (BSS) buffer before CBMEM is reinitialized. */
89 init_console_ptr(static_console, sizeof(static_console));
90 }
Aaron Durbin2ad6bd22013-05-10 00:45:37 -050091}
92
93void cbmemc_tx_byte(unsigned char data)
94{
Raul E Rangelbf993112022-01-11 12:48:50 -070095 if (!current_console || !current_console->size || console_paused)
Vadim Bendebury32da8be2011-09-29 17:27:15 -070096 return;
97
Patrick Georgia8582c42019-11-30 10:49:17 +010098 u32 flags = current_console->cursor & ~CURSOR_MASK;
99 u32 cursor = current_console->cursor & CURSOR_MASK;
Julius Wernerd67c6872017-02-02 17:32:00 -0800100
Patrick Georgia8582c42019-11-30 10:49:17 +0100101 current_console->body[cursor++] = data;
102 if (cursor >= current_console->size) {
Julius Wernerd67c6872017-02-02 17:32:00 -0800103 cursor = 0;
104 flags |= OVERFLOW;
105 }
106
Patrick Georgia8582c42019-11-30 10:49:17 +0100107 current_console->cursor = flags | cursor;
Vadim Bendebury32da8be2011-09-29 17:27:15 -0700108}
109
Raul Rangel03b1d3e2022-01-21 16:46:55 +0000110/*
111 * Copy the current console buffer (either from the cache as RAM area or from
112 * the static buffer, pointed at by src_cons_p) into the newly initialized CBMEM
113 * console. The use of cbmemc_tx_byte() ensures that all special cases for the
114 * target console (e.g. overflow) will be handled. If there had been an
115 * overflow in the source console, log a message to that effect.
116 */
117static void copy_console_buffer(struct cbmem_console *src_cons_p)
118{
119 u32 c;
120
121 if (!src_cons_p)
122 return;
123
124 if (src_cons_p->cursor & OVERFLOW) {
125 const char overflow_warning[] = "\n*** Pre-CBMEM " ENV_STRING
126 " console overflowed, log truncated! ***\n";
127 for (c = 0; c < sizeof(overflow_warning) - 1; c++)
128 cbmemc_tx_byte(overflow_warning[c]);
129 for (c = src_cons_p->cursor & CURSOR_MASK;
130 c < src_cons_p->size; c++)
131 cbmemc_tx_byte(src_cons_p->body[c]);
132 }
133
134 for (c = 0; c < (src_cons_p->cursor & CURSOR_MASK); c++)
135 cbmemc_tx_byte(src_cons_p->body[c]);
136
137 /* Invalidate the source console, so it will be reinitialized on the
138 next reboot. Otherwise, we might copy the same bytes again. */
139 src_cons_p->size = 0;
140}
141
Raul E Rangel1e1aa0c2022-01-13 09:46:21 -0700142void cbmemc_copy_in(void *buffer, size_t size)
143{
144 struct cbmem_console *previous = (void *)buffer;
145
146 if (!buffer_valid(previous, size))
147 return;
148
149 copy_console_buffer(previous);
150}
151
Aaron Durbin41607a42015-06-09 13:54:10 -0500152static void cbmemc_reinit(int is_recovery)
Vadim Bendebury32da8be2011-09-29 17:27:15 -0700153{
Aaron Durbind70bf7c2015-04-20 15:24:19 -0500154 const size_t size = CONFIG_CONSOLE_CBMEM_BUFFER_SIZE;
Julius Wernerd67c6872017-02-02 17:32:00 -0800155 /* If CBMEM entry already existed, old contents are not altered. */
156 struct cbmem_console *cbmem_cons_p = cbmem_add(CBMEM_ID_CONSOLE, size);
Patrick Georgia8582c42019-11-30 10:49:17 +0100157 struct cbmem_console *previous_cons_p = current_console;
Vadim Bendebury32da8be2011-09-29 17:27:15 -0700158
Julius Wernerd67c6872017-02-02 17:32:00 -0800159 init_console_ptr(cbmem_cons_p, size);
160 copy_console_buffer(previous_cons_p);
Vadim Bendebury32da8be2011-09-29 17:27:15 -0700161}
Julius Werner913a47a2021-05-20 17:00:46 -0700162
163/* Run the romstage hook early so that the console region is one of the earliest created, and
164 therefore more likely to stay in the same place even across different boot modes where some
165 other regions may sometimes not get created (e.g. RW_MCACHE in vboot recovery mode). */
166ROMSTAGE_CBMEM_INIT_HOOK_EARLY(cbmemc_reinit)
Kyösti Mälkki4fbac462015-01-07 04:48:43 +0200167RAMSTAGE_CBMEM_INIT_HOOK(cbmemc_reinit)
Aaron Durbin1e9a9142016-09-16 16:23:21 -0500168POSTCAR_CBMEM_INIT_HOOK(cbmemc_reinit)
Aaron Durbind70bf7c2015-04-20 15:24:19 -0500169
Julius Wernercd49cce2019-03-05 16:53:33 -0800170#if CONFIG(CONSOLE_CBMEM_DUMP_TO_UART)
Raul E Rangel41a1a9e2022-01-11 12:44:38 -0700171void cbmem_dump_console_to_uart(void)
Vadim Bendebury6e20e2f2015-04-10 18:04:04 -0700172{
Julius Wernerd67c6872017-02-02 17:32:00 -0800173 u32 cursor;
Raul E Rangel6ec3dd22022-01-21 13:34:21 -0700174 unsigned int console_index;
175
Patrick Georgia8582c42019-11-30 10:49:17 +0100176 if (!current_console)
Vadim Bendebury6e20e2f2015-04-10 18:04:04 -0700177 return;
178
Raul E Rangel6ec3dd22022-01-21 13:34:21 -0700179 console_index = get_uart_for_console();
180
181 uart_init(console_index);
182 if (current_console->cursor & OVERFLOW) {
Patrick Georgia8582c42019-11-30 10:49:17 +0100183 for (cursor = current_console->cursor & CURSOR_MASK;
Raul E Rangel6ec3dd22022-01-21 13:34:21 -0700184 cursor < current_console->size; cursor++) {
Julius Werner984d03c2022-01-21 15:33:47 -0800185 if (BIOS_LOG_IS_MARKER(current_console->body[cursor]))
186 continue;
Raul E Rangel6ec3dd22022-01-21 13:34:21 -0700187 if (current_console->body[cursor] == '\n')
188 uart_tx_byte(console_index, '\r');
189 uart_tx_byte(console_index, current_console->body[cursor]);
190 }
191 }
192 for (cursor = 0; cursor < (current_console->cursor & CURSOR_MASK); cursor++) {
Julius Werner984d03c2022-01-21 15:33:47 -0800193 if (BIOS_LOG_IS_MARKER(current_console->body[cursor]))
194 continue;
Raul E Rangel6ec3dd22022-01-21 13:34:21 -0700195 if (current_console->body[cursor] == '\n')
196 uart_tx_byte(console_index, '\r');
197 uart_tx_byte(console_index, current_console->body[cursor]);
198 }
Vadim Bendebury6e20e2f2015-04-10 18:04:04 -0700199}
200#endif
Raul E Rangelbf993112022-01-11 12:48:50 -0700201
202void cbmem_dump_console(void)
203{
204 u32 cursor;
205 if (!current_console)
206 return;
207
208 console_paused = true;
209
210 if (current_console->cursor & OVERFLOW)
211 for (cursor = current_console->cursor & CURSOR_MASK;
212 cursor < current_console->size; cursor++)
Julius Werner984d03c2022-01-21 15:33:47 -0800213 if (!BIOS_LOG_IS_MARKER(current_console->body[cursor]))
214 do_putchar(current_console->body[cursor]);
Raul E Rangelbf993112022-01-11 12:48:50 -0700215 for (cursor = 0; cursor < (current_console->cursor & CURSOR_MASK); cursor++)
Julius Werner984d03c2022-01-21 15:33:47 -0800216 if (!BIOS_LOG_IS_MARKER(current_console->body[cursor]))
217 do_putchar(current_console->body[cursor]);
Raul E Rangelbf993112022-01-11 12:48:50 -0700218
219 console_paused = false;
220}