blob: 641824f9429c99702f8970f4a1913459f6dc869e [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>
Vadim Bendebury6e20e2f2015-04-10 18:04:04 -07004#include <console/uart.h>
Vadim Bendebury32da8be2011-09-29 17:27:15 -07005#include <cbmem.h>
Julius Wernerec5e5e02014-08-20 15:29:56 -07006#include <symbols.h>
Vadim Bendebury32da8be2011-09-29 17:27:15 -07007
8/*
9 * Structure describing console buffer. It is overlaid on a flat memory area,
Julius Wernerd67c6872017-02-02 17:32:00 -080010 * with body covering the extent of the memory. Once the buffer is full,
11 * output will wrap back around to the start of the buffer. The high bit of the
12 * cursor field gets set to indicate that this happened. If the underlying
13 * storage allows this, the buffer will persist across multiple boots and append
14 * to the previous log.
Julius Wernera915cea2017-04-24 17:08:06 -070015 *
16 * NOTE: These are known implementations accessing this console that need to be
17 * updated in case of structure/API changes:
18 *
19 * cbmem: [coreboot]/src/util/cbmem/cbmem.c
20 * libpayload: [coreboot]/payloads/libpayload/drivers/cbmem_console.c
21 * coreinfo: [coreboot]/payloads/coreinfo/bootlog_module.c
22 * Linux: drivers/firmware/google/memconsole-coreboot.c
23 * SeaBIOS: src/firmware/coreboot.c
24 * GRUB: grub-core/term/i386/coreboot/cbmemc.c
Vadim Bendebury32da8be2011-09-29 17:27:15 -070025 */
26struct cbmem_console {
Julius Wernerd09dc6b2017-02-03 12:45:21 -080027 u32 size;
28 u32 cursor;
29 u8 body[0];
Stefan Reinauer6a001132017-07-13 02:20:27 +020030} __packed;
Vadim Bendebury32da8be2011-09-29 17:27:15 -070031
Julius Wernerd67c6872017-02-02 17:32:00 -080032#define MAX_SIZE (1 << 28) /* can't be changed without breaking readers! */
33#define CURSOR_MASK (MAX_SIZE - 1) /* bits 31-28 are reserved for flags */
Ryan Salsamendifce582f2017-06-09 19:47:57 -070034#define OVERFLOW (1UL << 31) /* set if in ring-buffer mode */
Julius Wernerd67c6872017-02-02 17:32:00 -080035_Static_assert(CONFIG_CONSOLE_CBMEM_BUFFER_SIZE <= MAX_SIZE,
36 "cbmem_console format cannot support buffers larger than 256MB!");
Aaron Durbin2ad6bd22013-05-10 00:45:37 -050037
Patrick Georgia8582c42019-11-30 10:49:17 +010038static struct cbmem_console *current_console;
Kyösti Mälkki8659e402014-12-21 08:55:47 +020039
Vadim Bendebury32da8be2011-09-29 17:27:15 -070040/*
41 * While running from ROM, before DRAM is initialized, some area in cache as
Elyes HAOUAS91e0e3c2016-07-30 15:51:13 +020042 * RAM space is used for the console buffer storage. The size and location of
Julius Wernerec5e5e02014-08-20 15:29:56 -070043 * the area are defined by the linker script with _(e)preram_cbmem_console.
Kyösti Mälkkie3acc8f2019-09-13 10:49:20 +030044 *
Kyösti Mälkki513a1a82018-06-03 12:29:50 +030045 * When running from RAM, some console output is generated before CBMEM is
Vadim Bendebury32da8be2011-09-29 17:27:15 -070046 * reinitialized. This static buffer is used to store that output temporarily,
47 * to be concatenated with the CBMEM console buffer contents accumulated
48 * during the ROM stage, once CBMEM becomes available at RAM stage.
49 */
Stefan Reinauer19d06b22013-09-09 11:22:18 -070050
Stefan Reinauer19d06b22013-09-09 11:22:18 -070051#define STATIC_CONSOLE_SIZE 1024
Stefan Reinauer19d06b22013-09-09 11:22:18 -070052static u8 static_console[STATIC_CONSOLE_SIZE];
Vadim Bendebury32da8be2011-09-29 17:27:15 -070053
Julius Wernerd67c6872017-02-02 17:32:00 -080054static int buffer_valid(struct cbmem_console *cbm_cons_p, u32 total_space)
55{
56 return (cbm_cons_p->cursor & CURSOR_MASK) < cbm_cons_p->size &&
57 cbm_cons_p->size <= MAX_SIZE &&
58 cbm_cons_p->size == total_space - sizeof(struct cbmem_console);
59}
60
61static void init_console_ptr(void *storage, u32 total_space)
Aaron Durbin2ad6bd22013-05-10 00:45:37 -050062{
63 struct cbmem_console *cbm_cons_p = storage;
64
Julius Wernerd67c6872017-02-02 17:32:00 -080065 if (!cbm_cons_p || total_space <= sizeof(struct cbmem_console)) {
Patrick Georgia8582c42019-11-30 10:49:17 +010066 current_console = NULL;
Kyösti Mälkki8659e402014-12-21 08:55:47 +020067 return;
68 }
69
Julius Wernerd67c6872017-02-02 17:32:00 -080070 if (!buffer_valid(cbm_cons_p, total_space)) {
Julius Wernerd09dc6b2017-02-03 12:45:21 -080071 cbm_cons_p->size = total_space - sizeof(struct cbmem_console);
72 cbm_cons_p->cursor = 0;
Kyösti Mälkki8659e402014-12-21 08:55:47 +020073 }
Kyösti Mälkki8659e402014-12-21 08:55:47 +020074
Patrick Georgia8582c42019-11-30 10:49:17 +010075 current_console = cbm_cons_p;
Aaron Durbin2ad6bd22013-05-10 00:45:37 -050076}
77
78void cbmemc_init(void)
79{
Kyösti Mälkkie3acc8f2019-09-13 10:49:20 +030080 if (ENV_ROMSTAGE_OR_BEFORE) {
81 /* Pre-RAM environments use special buffer placed by linker script. */
82 init_console_ptr(_preram_cbmem_console, REGION_SIZE(preram_cbmem_console));
83 } else {
84 /* Post-RAM uses static (BSS) buffer before CBMEM is reinitialized. */
85 init_console_ptr(static_console, sizeof(static_console));
86 }
Aaron Durbin2ad6bd22013-05-10 00:45:37 -050087}
88
89void cbmemc_tx_byte(unsigned char data)
90{
Patrick Georgia8582c42019-11-30 10:49:17 +010091 if (!current_console || !current_console->size)
Vadim Bendebury32da8be2011-09-29 17:27:15 -070092 return;
93
Patrick Georgia8582c42019-11-30 10:49:17 +010094 u32 flags = current_console->cursor & ~CURSOR_MASK;
95 u32 cursor = current_console->cursor & CURSOR_MASK;
Julius Wernerd67c6872017-02-02 17:32:00 -080096
Patrick Georgia8582c42019-11-30 10:49:17 +010097 current_console->body[cursor++] = data;
98 if (cursor >= current_console->size) {
Julius Wernerd67c6872017-02-02 17:32:00 -080099 cursor = 0;
100 flags |= OVERFLOW;
101 }
102
Patrick Georgia8582c42019-11-30 10:49:17 +0100103 current_console->cursor = flags | cursor;
Vadim Bendebury32da8be2011-09-29 17:27:15 -0700104}
105
106/*
Julius Wernerd67c6872017-02-02 17:32:00 -0800107 * Copy the current console buffer (either from the cache as RAM area or from
108 * the static buffer, pointed at by src_cons_p) into the newly initialized CBMEM
109 * console. The use of cbmemc_tx_byte() ensures that all special cases for the
110 * target console (e.g. overflow) will be handled. If there had been an
111 * overflow in the source console, log a message to that effect.
Vadim Bendebury32da8be2011-09-29 17:27:15 -0700112 */
Julius Wernerd67c6872017-02-02 17:32:00 -0800113static void copy_console_buffer(struct cbmem_console *src_cons_p)
Vadim Bendebury32da8be2011-09-29 17:27:15 -0700114{
Julius Wernerd67c6872017-02-02 17:32:00 -0800115 u32 c;
Aaron Durbin2ad6bd22013-05-10 00:45:37 -0500116
Julius Wernerd67c6872017-02-02 17:32:00 -0800117 if (!src_cons_p)
118 return;
Vadim Bendebury32da8be2011-09-29 17:27:15 -0700119
Julius Wernerd67c6872017-02-02 17:32:00 -0800120 if (src_cons_p->cursor & OVERFLOW) {
Julius Wernerd906bb62017-05-16 13:54:18 -0700121 const char overflow_warning[] = "\n*** Pre-CBMEM " ENV_STRING
122 " console overflowed, log truncated! ***\n";
Julius Wernerd67c6872017-02-02 17:32:00 -0800123 for (c = 0; c < sizeof(overflow_warning) - 1; c++)
124 cbmemc_tx_byte(overflow_warning[c]);
125 for (c = src_cons_p->cursor & CURSOR_MASK;
126 c < src_cons_p->size; c++)
127 cbmemc_tx_byte(src_cons_p->body[c]);
Kyösti Mälkkia3c5ba32013-11-27 17:51:31 +0200128 }
Vadim Bendebury32da8be2011-09-29 17:27:15 -0700129
Julius Wernerd67c6872017-02-02 17:32:00 -0800130 for (c = 0; c < (src_cons_p->cursor & CURSOR_MASK); c++)
131 cbmemc_tx_byte(src_cons_p->body[c]);
Vadim Bendebury32da8be2011-09-29 17:27:15 -0700132
Julius Wernerd67c6872017-02-02 17:32:00 -0800133 /* Invalidate the source console, so it will be reinitialized on the
134 next reboot. Otherwise, we might copy the same bytes again. */
135 src_cons_p->size = 0;
Vadim Bendebury32da8be2011-09-29 17:27:15 -0700136}
137
Aaron Durbin41607a42015-06-09 13:54:10 -0500138static void cbmemc_reinit(int is_recovery)
Vadim Bendebury32da8be2011-09-29 17:27:15 -0700139{
Aaron Durbind70bf7c2015-04-20 15:24:19 -0500140 const size_t size = CONFIG_CONSOLE_CBMEM_BUFFER_SIZE;
Julius Wernerd67c6872017-02-02 17:32:00 -0800141 /* If CBMEM entry already existed, old contents are not altered. */
142 struct cbmem_console *cbmem_cons_p = cbmem_add(CBMEM_ID_CONSOLE, size);
Patrick Georgia8582c42019-11-30 10:49:17 +0100143 struct cbmem_console *previous_cons_p = current_console;
Vadim Bendebury32da8be2011-09-29 17:27:15 -0700144
Julius Wernerd67c6872017-02-02 17:32:00 -0800145 init_console_ptr(cbmem_cons_p, size);
146 copy_console_buffer(previous_cons_p);
Vadim Bendebury32da8be2011-09-29 17:27:15 -0700147}
Kyösti Mälkki4fbac462015-01-07 04:48:43 +0200148ROMSTAGE_CBMEM_INIT_HOOK(cbmemc_reinit)
149RAMSTAGE_CBMEM_INIT_HOOK(cbmemc_reinit)
Aaron Durbin1e9a9142016-09-16 16:23:21 -0500150POSTCAR_CBMEM_INIT_HOOK(cbmemc_reinit)
Aaron Durbind70bf7c2015-04-20 15:24:19 -0500151
Julius Wernercd49cce2019-03-05 16:53:33 -0800152#if CONFIG(CONSOLE_CBMEM_DUMP_TO_UART)
Vadim Bendebury6e20e2f2015-04-10 18:04:04 -0700153void cbmem_dump_console(void)
154{
Julius Wernerd67c6872017-02-02 17:32:00 -0800155 u32 cursor;
Patrick Georgia8582c42019-11-30 10:49:17 +0100156 if (!current_console)
Vadim Bendebury6e20e2f2015-04-10 18:04:04 -0700157 return;
158
159 uart_init(0);
Patrick Georgia8582c42019-11-30 10:49:17 +0100160 if (current_console->cursor & OVERFLOW)
161 for (cursor = current_console->cursor & CURSOR_MASK;
162 cursor < current_console->size; cursor++)
163 uart_tx_byte(0, current_console->body[cursor]);
164 for (cursor = 0; cursor < (current_console->cursor & CURSOR_MASK); cursor++)
165 uart_tx_byte(0, current_console->body[cursor]);
Vadim Bendebury6e20e2f2015-04-10 18:04:04 -0700166}
167#endif