kboot: Expose m1n1 console log in phram MTD reserved memory node

This registers a log buffer IODEV similar to the frame buffer IODEV. It
is using a console IODEV to allow writing to the buffer until m1n1 jumps
to the next stage. This allows also to increase the buffer size without
increasing m1n1's size. The current CONSOLE_BUFFER_SIZE of 8k is not
large enough to hold the entire log of executing m1n1 under the
hypervisor on the M1 Ultra Mac Studio.

Signed-off-by: Janne Grunau <j@jannau.net>
This commit is contained in:
Janne Grunau 2024-08-10 23:31:29 +02:00 committed by Hector Martin
parent 1d5556ccf3
commit 48837f4d47
3 changed files with 73 additions and 5 deletions

View file

@ -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))

View file

@ -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 {

View file

@ -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())