From d67c6876b521d784e38ea91b5a1828a24c9cb1c8 Mon Sep 17 00:00:00 2001 From: Julius Werner Date: Thu, 2 Feb 2017 17:32:00 -0800 Subject: 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 Reviewed-on: https://review.coreboot.org/18301 Tested-by: build bot (Jenkins) Reviewed-by: Aaron Durbin --- payloads/libpayload/drivers/cbmem_console.c | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) (limited to 'payloads/libpayload/drivers') 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); } -- cgit v1.2.3