blob: a7d67a39817981fa295414d09022edc5bc897fb6 [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}
Julius Werner913a47a2021-05-20 17:00:46 -0700148
149/* Run the romstage hook early so that the console region is one of the earliest created, and
150 therefore more likely to stay in the same place even across different boot modes where some
151 other regions may sometimes not get created (e.g. RW_MCACHE in vboot recovery mode). */
152ROMSTAGE_CBMEM_INIT_HOOK_EARLY(cbmemc_reinit)
Kyösti Mälkki4fbac462015-01-07 04:48:43 +0200153RAMSTAGE_CBMEM_INIT_HOOK(cbmemc_reinit)
Aaron Durbin1e9a9142016-09-16 16:23:21 -0500154POSTCAR_CBMEM_INIT_HOOK(cbmemc_reinit)
Aaron Durbind70bf7c2015-04-20 15:24:19 -0500155
Julius Wernercd49cce2019-03-05 16:53:33 -0800156#if CONFIG(CONSOLE_CBMEM_DUMP_TO_UART)
Vadim Bendebury6e20e2f2015-04-10 18:04:04 -0700157void cbmem_dump_console(void)
158{
Julius Wernerd67c6872017-02-02 17:32:00 -0800159 u32 cursor;
Patrick Georgia8582c42019-11-30 10:49:17 +0100160 if (!current_console)
Vadim Bendebury6e20e2f2015-04-10 18:04:04 -0700161 return;
162
163 uart_init(0);
Patrick Georgia8582c42019-11-30 10:49:17 +0100164 if (current_console->cursor & OVERFLOW)
165 for (cursor = current_console->cursor & CURSOR_MASK;
166 cursor < current_console->size; cursor++)
167 uart_tx_byte(0, current_console->body[cursor]);
168 for (cursor = 0; cursor < (current_console->cursor & CURSOR_MASK); cursor++)
169 uart_tx_byte(0, current_console->body[cursor]);
Vadim Bendebury6e20e2f2015-04-10 18:04:04 -0700170}
171#endif