arch/x86/gdt: Correct format of multi-line comment
[coreboot.git] / src / lib / cbmem_console.c
blobd9716700bb7d691dc521b31df283f99030c2f9da
1 /*
2 * This file is part of the coreboot project.
4 * Copyright (C) 2011 The ChromiumOS Authors. All rights reserved.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
16 #include <compiler.h>
17 #include <console/console.h>
18 #include <console/cbmem_console.h>
19 #include <console/uart.h>
20 #include <cbmem.h>
21 #include <arch/early_variables.h>
22 #include <symbols.h>
23 #include <string.h>
26 * Structure describing console buffer. It is overlaid on a flat memory area,
27 * with body covering the extent of the memory. Once the buffer is full,
28 * output will wrap back around to the start of the buffer. The high bit of the
29 * cursor field gets set to indicate that this happened. If the underlying
30 * storage allows this, the buffer will persist across multiple boots and append
31 * to the previous log.
33 * NOTE: These are known implementations accessing this console that need to be
34 * updated in case of structure/API changes:
36 * cbmem: [coreboot]/src/util/cbmem/cbmem.c
37 * libpayload: [coreboot]/payloads/libpayload/drivers/cbmem_console.c
38 * coreinfo: [coreboot]/payloads/coreinfo/bootlog_module.c
39 * Linux: drivers/firmware/google/memconsole-coreboot.c
40 * SeaBIOS: src/firmware/coreboot.c
41 * GRUB: grub-core/term/i386/coreboot/cbmemc.c
43 struct cbmem_console {
44 u32 size;
45 u32 cursor;
46 u8 body[0];
47 } __packed;
49 #define MAX_SIZE (1 << 28) /* can't be changed without breaking readers! */
50 #define CURSOR_MASK (MAX_SIZE - 1) /* bits 31-28 are reserved for flags */
51 #define OVERFLOW (1UL << 31) /* set if in ring-buffer mode */
52 _Static_assert(CONFIG_CONSOLE_CBMEM_BUFFER_SIZE <= MAX_SIZE,
53 "cbmem_console format cannot support buffers larger than 256MB!");
55 static struct cbmem_console *cbmem_console_p CAR_GLOBAL;
57 #ifdef __PRE_RAM__
59 * While running from ROM, before DRAM is initialized, some area in cache as
60 * RAM space is used for the console buffer storage. The size and location of
61 * the area are defined by the linker script with _(e)preram_cbmem_console.
64 #else
67 * When running from RAM, a lot of console output is generated before CBMEM is
68 * reinitialized. This static buffer is used to store that output temporarily,
69 * to be concatenated with the CBMEM console buffer contents accumulated
70 * during the ROM stage, once CBMEM becomes available at RAM stage.
73 #if IS_ENABLED(CONFIG_EARLY_CBMEM_INIT)
74 #define STATIC_CONSOLE_SIZE 1024
75 #else
76 #define STATIC_CONSOLE_SIZE CONFIG_CONSOLE_CBMEM_BUFFER_SIZE
77 #endif
78 static u8 static_console[STATIC_CONSOLE_SIZE];
79 #endif
81 static struct cbmem_console *current_console(void)
83 return car_sync_var(cbmem_console_p);
86 static void current_console_set(struct cbmem_console *new_console_p)
88 car_set_var(cbmem_console_p, new_console_p);
91 static int buffer_valid(struct cbmem_console *cbm_cons_p, u32 total_space)
93 return (cbm_cons_p->cursor & CURSOR_MASK) < cbm_cons_p->size &&
94 cbm_cons_p->size <= MAX_SIZE &&
95 cbm_cons_p->size == total_space - sizeof(struct cbmem_console);
98 static void init_console_ptr(void *storage, u32 total_space)
100 struct cbmem_console *cbm_cons_p = storage;
102 if (!cbm_cons_p || total_space <= sizeof(struct cbmem_console)) {
103 current_console_set(NULL);
104 return;
107 if (!buffer_valid(cbm_cons_p, total_space)) {
108 cbm_cons_p->size = total_space - sizeof(struct cbmem_console);
109 cbm_cons_p->cursor = 0;
112 current_console_set(cbm_cons_p);
115 void cbmemc_init(void)
117 #ifdef __PRE_RAM__
118 /* Pre-RAM environments use special buffer placed by linker script. */
119 init_console_ptr(_preram_cbmem_console, _preram_cbmem_console_size);
120 #else
121 /* Post-RAM uses static (BSS) buffer before CBMEM is reinitialized. */
122 init_console_ptr(static_console, sizeof(static_console));
123 #endif
126 void cbmemc_tx_byte(unsigned char data)
128 struct cbmem_console *cbm_cons_p = current_console();
130 if (!cbm_cons_p || !cbm_cons_p->size)
131 return;
133 u32 flags = cbm_cons_p->cursor & ~CURSOR_MASK;
134 u32 cursor = cbm_cons_p->cursor & CURSOR_MASK;
136 cbm_cons_p->body[cursor++] = data;
137 if (cursor >= cbm_cons_p->size) {
138 cursor = 0;
139 flags |= OVERFLOW;
142 cbm_cons_p->cursor = flags | cursor;
146 * Copy the current console buffer (either from the cache as RAM area or from
147 * the static buffer, pointed at by src_cons_p) into the newly initialized CBMEM
148 * console. The use of cbmemc_tx_byte() ensures that all special cases for the
149 * target console (e.g. overflow) will be handled. If there had been an
150 * overflow in the source console, log a message to that effect.
152 static void copy_console_buffer(struct cbmem_console *src_cons_p)
154 u32 c;
156 if (!src_cons_p)
157 return;
159 if (src_cons_p->cursor & OVERFLOW) {
160 const char overflow_warning[] = "\n*** Pre-CBMEM " ENV_STRING
161 " console overflowed, log truncated! ***\n";
162 for (c = 0; c < sizeof(overflow_warning) - 1; c++)
163 cbmemc_tx_byte(overflow_warning[c]);
164 for (c = src_cons_p->cursor & CURSOR_MASK;
165 c < src_cons_p->size; c++)
166 cbmemc_tx_byte(src_cons_p->body[c]);
169 for (c = 0; c < (src_cons_p->cursor & CURSOR_MASK); c++)
170 cbmemc_tx_byte(src_cons_p->body[c]);
172 /* Invalidate the source console, so it will be reinitialized on the
173 next reboot. Otherwise, we might copy the same bytes again. */
174 src_cons_p->size = 0;
177 static void cbmemc_reinit(int is_recovery)
179 const size_t size = CONFIG_CONSOLE_CBMEM_BUFFER_SIZE;
180 /* If CBMEM entry already existed, old contents are not altered. */
181 struct cbmem_console *cbmem_cons_p = cbmem_add(CBMEM_ID_CONSOLE, size);
182 struct cbmem_console *previous_cons_p = current_console();
184 init_console_ptr(cbmem_cons_p, size);
185 copy_console_buffer(previous_cons_p);
187 ROMSTAGE_CBMEM_INIT_HOOK(cbmemc_reinit)
188 RAMSTAGE_CBMEM_INIT_HOOK(cbmemc_reinit)
189 POSTCAR_CBMEM_INIT_HOOK(cbmemc_reinit)
191 #if IS_ENABLED(CONFIG_CONSOLE_CBMEM_DUMP_TO_UART)
192 void cbmem_dump_console(void)
194 struct cbmem_console *cbm_cons_p;
195 u32 cursor;
197 cbm_cons_p = current_console();
198 if (!cbm_cons_p)
199 return;
201 uart_init(0);
202 if (cbm_cons_p->cursor & OVERFLOW)
203 for (cursor = cbm_cons_p->cursor & CURSOR_MASK;
204 cursor < cbm_cons_p->size; cursor++)
205 uart_tx_byte(0, cbm_cons_p->body[cursor]);
206 for (cursor = 0; cursor < (cbm_cons_p->cursor & CURSOR_MASK); cursor++)
207 uart_tx_byte(0, cbm_cons_p->body[cursor]);
209 #endif