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 /util/cbmem | |
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 'util/cbmem')
-rw-r--r-- | util/cbmem/cbmem.c | 63 |
1 files changed, 39 insertions, 24 deletions
diff --git a/util/cbmem/cbmem.c b/util/cbmem/cbmem.c index e60505222a..7b7f10d53f 100644 --- a/util/cbmem/cbmem.c +++ b/util/cbmem/cbmem.c @@ -601,52 +601,67 @@ static void dump_timestamps(int mach_readable) unmap_memory(); } +struct cbmem_console { + u32 size; + u32 cursor; + u8 body[0]; +} __attribute__ ((__packed__)); + +#define CBMC_CURSOR_MASK ((1 << 28) - 1) +#define CBMC_OVERFLOW (1 << 31) + /* dump the cbmem console */ static void dump_console(void) { - void *console_p; + struct cbmem_console *console_p; char *console_c; - uint32_t size; - uint32_t cursor; + size_t size, cursor; if (console.tag != LB_TAG_CBMEM_CONSOLE) { fprintf(stderr, "No console found in coreboot table.\n"); return; } - console_p = map_memory_size((unsigned long)console.cbmem_addr, - 2 * sizeof(uint32_t), 1); - /* The in-memory format of the console area is: - * u32 size - * u32 cursor - * char console[size] - * Hence we have to add 8 to get to the actual console string. - */ - size = ((uint32_t *)console_p)[0]; - cursor = ((uint32_t *)console_p)[1]; - /* Cursor continues to go on even after no more data fits in - * the buffer but the data is dropped in this case. - */ - if (size > cursor) + size = sizeof(*console_p); + console_p = map_memory_size((unsigned long)console.cbmem_addr, size, 1); + cursor = console_p->cursor & CBMC_CURSOR_MASK; + if (!(console_p->cursor & CBMC_OVERFLOW) && cursor < console_p->size) size = cursor; - console_c = calloc(1, size + 1); + else + size = console_p->size; unmap_memory(); + + console_c = malloc(size + 1); if (!console_c) { fprintf(stderr, "Not enough memory for console.\n"); exit(1); } + console_c[size] = '\0'; console_p = map_memory_size((unsigned long)console.cbmem_addr, - size + sizeof(size) + sizeof(cursor), 1); - aligned_memcpy(console_c, console_p + 8, size); + size + sizeof(*console_p), 1); + if (console_p->cursor & CBMC_OVERFLOW) { + if (cursor >= size) { + printf("cbmem: ERROR: CBMEM console struct is illegal, " + "output may be corrupt or out of order!\n\n"); + cursor = 0; + } + aligned_memcpy(console_c, console_p->body + cursor, + size - cursor); + aligned_memcpy(console_c + size - cursor, + console_p->body, cursor); + } else { + aligned_memcpy(console_c, console_p->body, size); + } + /* Slight memory corruption may occur between reboots and give us a few + unprintable characters like '\0'. Replace them with '?' on output. */ + for (cursor = 0; cursor < size; cursor++) + if (!isprint(console_c[cursor]) && !isspace(console_c[cursor])) + console_c[cursor] = '?'; printf("%s\n", console_c); - if (size < cursor) - printf("%d %s lost\n", cursor - size, - (cursor - size) == 1 ? "byte":"bytes"); free(console_c); - unmap_memory(); } |