diff options
author | Julius Werner <jwerner@chromium.org> | 2017-02-02 17:32:00 -0800 |
---|---|---|
committer | Julius Werner <jwerner@chromium.org> | 2017-04-20 00:29:07 +0200 |
commit | d67c6876b521d784e38ea91b5a1828a24c9cb1c8 (patch) | |
tree | 7dcf7baa1f5a1b11361eadef2d3b28ef42e05c18 /payloads | |
parent | 2d35809530c5112276f713328bf964662488f793 (diff) |
Turn CBMEM console into a ring buffer that can persist across reboots
This patch allows the CBMEM console to persist across reboots, which
should greatly help post factum debugging of issues involving multiple
reboots. In order to prevent the console from filling up, it will
instead operate as a ring buffer that continues to evict the oldest
lines once full. (This means that if even a single boot doesn't fit into
the buffer, we will now drop the oldest lines whereas previous code
would've dropped the newest lines instead.)
The console control structure is modified in a sorta
backwards-compatible way, so that new readers can continue to work with
old console buffers and vice versa. When an old reader reads a new
buffer that has already once overflowed (i.e. is operating in true ring
buffer mode) it will print lines out of order, but it will at least
still print out the whole console content and not do any illegal memory
accesses (assuming it correctly implemented cursor overflow as it was
already possible before this patch).
BUG=chromium:651966
TEST=Rebooted and confirmed output repeatedly on a Kevin and a Falco.
Also confirmed correct behavior across suspend/resume for the latter.
Change-Id: Ifcbf59d58e1ad20995b98d111c4647281fbb45ff
Signed-off-by: Julius Werner <jwerner@chromium.org>
Reviewed-on: https://review.coreboot.org/18301
Tested-by: build bot (Jenkins)
Reviewed-by: Aaron Durbin <adurbin@chromium.org>
Diffstat (limited to 'payloads')
-rw-r--r-- | payloads/coreinfo/bootlog_module.c | 45 | ||||
-rw-r--r-- | payloads/libpayload/drivers/cbmem_console.c | 27 |
2 files changed, 53 insertions, 19 deletions
diff --git a/payloads/coreinfo/bootlog_module.c b/payloads/coreinfo/bootlog_module.c index 1d990d1d0c..b3f0deeea5 100644 --- a/payloads/coreinfo/bootlog_module.c +++ b/payloads/coreinfo/bootlog_module.c @@ -35,6 +35,9 @@ struct cbmem_console { u8 body[0]; } __attribute__ ((__packed__)); +#define CURSOR_MASK ((1 << 28) - 1) +#define OVERFLOW (1 << 31) + static u32 char_width(char c, u32 cursor, u32 screen_width) { @@ -114,23 +117,28 @@ static int bootlog_module_init(void) } /* Extract console information */ char *buffer = (char *)(&(console->body)); - u32 buffer_size = console->size; - u32 cursor = console->cursor; + u32 size = console->size; + u32 cursor = console->cursor & CURSOR_MASK; - /* The cursor may be bigger than buffer size when the buffer is full */ - if (cursor >= buffer_size) { - cursor = buffer_size - 1; + /* The cursor may be bigger than buffer size with older console code */ + if (cursor >= size) { + cursor = size - 1; } /* Calculate how much characters will be displayed on screen */ - u32 chars_count = calculate_chars_count(buffer, cursor + 1, SCREEN_X, LINES_SHOWN); + u32 chars_count = calculate_chars_count(buffer, cursor, SCREEN_X, LINES_SHOWN); + u32 overflow_chars_count = 0; + if (console->cursor & OVERFLOW) { + overflow_chars_count = calculate_chars_count(buffer + cursor, + size - cursor, SCREEN_X, LINES_SHOWN); + } /* Sanity check, chars_count must be padded to full line */ - if (chars_count % SCREEN_X != 0) { + if (chars_count % SCREEN_X || overflow_chars_count % SCREEN_X) { return -2; } - g_lines_count = chars_count / SCREEN_X; + g_lines_count = (chars_count + overflow_chars_count) / SCREEN_X; g_max_cursor_line = MAX(g_lines_count - 1 - LINES_SHOWN, 0); g_buf = malloc(chars_count); @@ -138,17 +146,26 @@ static int bootlog_module_init(void) return -3; } - if (sanitize_buffer_for_display(buffer, cursor + 1, - g_buf, chars_count, - SCREEN_X) < 0) { - free(g_buf); - g_buf = NULL; - return -4; + if (console->cursor & OVERFLOW) { + if (sanitize_buffer_for_display(buffer + cursor, size - cursor, + g_buf, overflow_chars_count, SCREEN_X) < 0) { + goto err_free; + } + } + if (sanitize_buffer_for_display(buffer, cursor, + g_buf + overflow_chars_count, + chars_count, SCREEN_X) < 0) { + goto err_free; } /* TODO: Maybe a _cleanup hook where we call free()? */ return 0; + +err_free: + free(g_buf); + g_buf = NULL; + return -4; } static int bootlog_module_redraw(WINDOW *win) diff --git a/payloads/libpayload/drivers/cbmem_console.c b/payloads/libpayload/drivers/cbmem_console.c index 687344400c..76c2abb74d 100644 --- a/payloads/libpayload/drivers/cbmem_console.c +++ b/payloads/libpayload/drivers/cbmem_console.c @@ -36,6 +36,9 @@ struct cbmem_console { uint8_t body[0]; } __attribute__ ((__packed__)); +#define CURSOR_MASK ((1 << 28) - 1) +#define OVERFLOW (1 << 31) + static struct cbmem_console *cbmem_console_p; static struct console_output_driver cbmem_console_driver = @@ -43,18 +46,32 @@ static struct console_output_driver cbmem_console_driver = .write = &cbmem_console_write, }; +static void do_write(const void *buffer, size_t count) +{ + memcpy(cbmem_console_p->body + (cbmem_console_p->cursor & CURSOR_MASK), + buffer, count); + cbmem_console_p->cursor += count; +} + void cbmem_console_init(void) { cbmem_console_p = lib_sysinfo.cbmem_cons; - if (cbmem_console_p) + if (cbmem_console_p && cbmem_console_p->size) console_add_output_driver(&cbmem_console_driver); } void cbmem_console_write(const void *buffer, size_t count) { - if (cbmem_console_p->cursor + count >= cbmem_console_p->size) - return; + while ((cbmem_console_p->cursor & CURSOR_MASK) + count >= + cbmem_console_p->size) { + size_t still_fits = cbmem_console_p->size - + (cbmem_console_p->cursor & CURSOR_MASK); + do_write(buffer, still_fits); + cbmem_console_p->cursor &= ~CURSOR_MASK; + cbmem_console_p->cursor |= OVERFLOW; + buffer += still_fits; + count -= still_fits; + } - memcpy(cbmem_console_p->body + cbmem_console_p->cursor, buffer, count); - cbmem_console_p->cursor += count; + do_write(buffer, count); } |