diff --git a/src/iodev.c b/src/iodev.c index 7c03b9c51..cdf7d5533 100644 --- a/src/iodev.c +++ b/src/iodev.c @@ -18,17 +18,19 @@ extern struct iodev iodev_uart; extern struct iodev iodev_fb; +extern struct iodev iodev_log; extern struct iodev iodev_usb_vuart; -struct iodev *iodevs[IODEV_MAX] = { +struct iodev *iodevs[IODEV_NUM] = { [IODEV_UART] = &iodev_uart, [IODEV_FB] = &iodev_fb, [IODEV_USB_VUART] = &iodev_usb_vuart, + [IODEV_LOG] = &iodev_log, }; char con_buf[CONSOLE_BUFFER_SIZE]; size_t con_wp; -size_t con_rp[IODEV_MAX]; +size_t con_rp[IODEV_NUM]; void iodev_register_device(iodev_id_t id, struct iodev *dev) { @@ -173,7 +175,7 @@ void iodev_console_write(const void *buf, size_t length) in_iodev++; dprintf(" iodev_console_write() wp=%d\n", con_wp); - for (iodev_id_t id = 0; id < IODEV_MAX; id++) { + for (iodev_id_t id = 0; id < IODEV_NUM; id++) { if (!iodevs[id]) continue; @@ -275,7 +277,7 @@ void iodev_console_kick(void) { iodev_console_write(NULL, 0); - for (iodev_id_t id = 0; id < IODEV_MAX; id++) { + for (iodev_id_t id = 0; id < IODEV_NUM; id++) { if (!iodevs[id]) continue; if (!(iodevs[id]->usage & USAGE_CONSOLE)) @@ -287,7 +289,7 @@ void iodev_console_kick(void) void iodev_console_flush(void) { - for (iodev_id_t id = 0; id < IODEV_MAX; id++) { + for (iodev_id_t id = 0; id < IODEV_NUM; id++) { if (!iodevs[id]) continue; if (!(iodevs[id]->usage & USAGE_CONSOLE)) diff --git a/src/iodev.h b/src/iodev.h index 24187c715..4c8b06c05 100644 --- a/src/iodev.h +++ b/src/iodev.h @@ -14,6 +14,8 @@ typedef enum _iodev_id_t { IODEV_USB_VUART, IODEV_USB0, IODEV_MAX = IODEV_USB0 + USB_IODEV_COUNT, + IODEV_LOG = IODEV_MAX, // hidden log buffer iodev + IODEV_NUM, } iodev_id_t; typedef enum _iodev_usage_t { diff --git a/src/kboot.c b/src/kboot.c index 2b5fb3cc8..b2dca2ac1 100644 --- a/src/kboot.c +++ b/src/kboot.c @@ -11,6 +11,7 @@ #include "display.h" #include "exception.h" #include "firmware.h" +#include "iodev.h" #include "isp.h" #include "malloc.h" #include "mcc.h" @@ -2265,6 +2266,54 @@ int kboot_set_chosen(const char *name, const char *value) return i; } +#define LOGBUF_SIZE SZ_16K + +struct { + void *buffer; + size_t wp; +} logbuf; + +static bool log_console_iodev_can_write(void *opaque) +{ + UNUSED(opaque); + return !!logbuf.buffer; +} + +static ssize_t log_console_iodev_write(void *opaque, const void *buf, size_t len) +{ + UNUSED(opaque); + + if (!logbuf.buffer) + return 0; + + ssize_t wrote = 0; + size_t remain = LOGBUF_SIZE - logbuf.wp; + while (remain < len) { + memcpy(logbuf.buffer + logbuf.wp, buf, remain); + logbuf.wp = 0; + wrote += remain; + buf += remain; + len -= remain; + remain = LOGBUF_SIZE; + } + memcpy(logbuf.buffer + logbuf.wp, buf, len); + wrote += len; + logbuf.wp = (logbuf.wp + len) % LOGBUF_SIZE; + + return wrote; +} + +const struct iodev_ops iodev_log_ops = { + .can_write = log_console_iodev_can_write, + .write = log_console_iodev_write, +}; + +struct iodev iodev_log = { + .ops = &iodev_log_ops, + .usage = USAGE_CONSOLE, + .lock = SPINLOCK_INIT, +}; + static int dt_setup_mtd_phram(void) { char node_name[64]; @@ -2279,6 +2328,20 @@ static int dt_setup_mtd_phram(void) bail("FDT: failed to setup ADT MTD phram label\n"); } + // init memory backed iodev for console log + logbuf.buffer = (void *)top_of_memory_alloc(LOGBUF_SIZE); + if (!logbuf.buffer) + bail("FDT: failed to allocate m1n1 log buffer\n"); + + snprintf(node_name, sizeof(node_name), "flash@%lx", (u64)logbuf.buffer); + node = dt_get_or_add_reserved_mem(node_name, "phram", false, (u64)logbuf.buffer, SZ_16K); + + if (node > 0) { + int ret = fdt_setprop_string(dt, node, "label", "m1n1_stage2.log"); + if (ret) + bail("FDT: failed to setup m1n1 log MTD phram label\n"); + } + return 0; } @@ -2307,6 +2370,7 @@ int kboot_prepare_dt(void *fdt) if (fdt_add_mem_rsv(dt, (u64)_base, ((u64)_end) - ((u64)_base))) bail("FDT: couldn't add reservation for m1n1\n"); + /* setup console log buffer early to cpature as much log as possible */ dt_setup_mtd_phram(); if (dt_set_chosen())