]> Projects (at) Tadryanom (dot) Me - AdrOS.git/commitdiff
feat: add kernel log ring buffer to kprintf (printk-style dmesg support)
authorTulio A M Mendes <[email protected]>
Tue, 10 Feb 2026 04:53:00 +0000 (01:53 -0300)
committerTulio A M Mendes <[email protected]>
Tue, 10 Feb 2026 04:53:00 +0000 (01:53 -0300)
Like Linux's printk, kprintf() now writes every formatted message
into a 16KB circular ring buffer (klog_buf) before dispatching to
console drivers (UART, VGA). This allows old messages to be
retrieved later via klog_read(), enabling dmesg functionality.

Design:
- 16KB static ring buffer (KLOG_BUF_SIZE)
- klog_head tracks next write position, klog_count tracks fill
- klog_append() writes into ring, capping at buffer size
- klog_read(out, size) copies oldest-to-newest into caller buffer
- Protected by dedicated klog_lock spinlock

Flow: kprintf() -> kvsnprintf() -> klog_append() -> console_write()

Passes: make, cppcheck, QEMU smoke test.

include/console.h
src/kernel/console.c

index 4f61e2512d6b9960158358376e9efdb9c07123c6..7bdbea4c14fffcb00745ac3ca7f4fa91556f56f7 100644 (file)
@@ -15,4 +15,6 @@ int ksnprintf(char* out, size_t out_size, const char* fmt, ...);
 
 void kprintf(const char* fmt, ...);
 
+size_t klog_read(char* out, size_t out_size);
+
 #endif
index 089211a1e8798b88d7ecdd6d80fb046c15b8f0e8..12d62337ff5d63569c14ae7b20be386a653991a7 100644 (file)
@@ -12,6 +12,24 @@ static spinlock_t g_console_lock = {0};
 static int g_console_uart_enabled = 1;
 static int g_console_vga_enabled = 0;
 
+/* ---- Kernel log ring buffer (like Linux __log_buf) ---- */
+#define KLOG_BUF_SIZE 16384
+static char klog_buf[KLOG_BUF_SIZE];
+static size_t klog_head = 0;   // next write position
+static size_t klog_count = 0;  // total bytes stored (capped at KLOG_BUF_SIZE)
+static spinlock_t klog_lock = {0};
+
+static void klog_append(const char* s, size_t len) {
+    for (size_t i = 0; i < len; i++) {
+        klog_buf[klog_head] = s[i];
+        klog_head = (klog_head + 1) % KLOG_BUF_SIZE;
+    }
+    klog_count += len;
+    if (klog_count > KLOG_BUF_SIZE) {
+        klog_count = KLOG_BUF_SIZE;
+    }
+}
+
 void console_init(void) {
     spinlock_init(&g_console_lock);
     g_console_uart_enabled = 1;
@@ -185,8 +203,45 @@ void kprintf(const char* fmt, ...) {
 
     va_list ap;
     va_start(ap, fmt);
-    (void)kvsnprintf(buf, sizeof(buf), fmt, ap);
+    int len = kvsnprintf(buf, sizeof(buf), fmt, ap);
     va_end(ap);
 
+    if (len > 0) {
+        size_t slen = (size_t)len;
+        if (slen >= sizeof(buf)) slen = sizeof(buf) - 1;
+
+        uintptr_t lf = spin_lock_irqsave(&klog_lock);
+        klog_append(buf, slen);
+        spin_unlock_irqrestore(&klog_lock, lf);
+    }
+
     console_write(buf);
 }
+
+size_t klog_read(char* out, size_t out_size) {
+    if (!out || out_size == 0) return 0;
+
+    uintptr_t flags = spin_lock_irqsave(&klog_lock);
+
+    size_t avail = klog_count;
+    if (avail > out_size - 1) avail = out_size - 1;
+
+    size_t start;
+    if (klog_count >= KLOG_BUF_SIZE) {
+        start = klog_head; // oldest byte is right after head
+    } else {
+        start = (klog_head + KLOG_BUF_SIZE - klog_count) % KLOG_BUF_SIZE;
+    }
+
+    // skip oldest bytes if avail < klog_count
+    size_t skip = klog_count - avail;
+    start = (start + skip) % KLOG_BUF_SIZE;
+
+    for (size_t i = 0; i < avail; i++) {
+        out[i] = klog_buf[(start + i) % KLOG_BUF_SIZE];
+    }
+    out[avail] = '\0';
+
+    spin_unlock_irqrestore(&klog_lock, flags);
+    return avail;
+}