diff options
author | Ian Moffett <ian@osmora.org> | 2025-05-29 22:53:41 -0400 |
---|---|---|
committer | Ian Moffett <ian@osmora.org> | 2025-05-29 22:53:41 -0400 |
commit | 81ffbaa6d5f2270a5c32d0f22da14606e0bd5394 (patch) | |
tree | c76adf7e00e58e35cd12540c4f4067b5b019cdb5 | |
parent | 6e26339f26b1fea1197a1d9599f5bbfb22755a97 (diff) |
kernel: syslog: Add kernel message buffer
Signed-off-by: Ian Moffett <ian@osmora.org>
-rw-r--r-- | sys/kern/kern_syslog.c | 93 |
1 files changed, 92 insertions, 1 deletions
diff --git a/sys/kern/kern_syslog.c b/sys/kern/kern_syslog.c index db50a3c..eb4fa8d 100644 --- a/sys/kern/kern_syslog.c +++ b/sys/kern/kern_syslog.c @@ -28,9 +28,14 @@ */ #include <sys/syslog.h> +#include <sys/cdefs.h> +#include <sys/sio.h> #include <sys/spinlock.h> +#include <sys/device.h> +#include <sys/errno.h> #include <dev/cons/cons.h> #include <dev/timer.h> +#include <fs/devfs.h> #include <stdarg.h> #include <string.h> @@ -46,10 +51,73 @@ #define USER_KMSG 0 #endif +#define KBUF_SIZE (1 << 16) + +/* Sanity check */ +__static_assert(KBUF_SIZE <= (1 << 16), "KBUF_SIZE too high!"); + /* Global logger lock */ static struct spinlock lock = {0}; +static struct spinlock kmsg_lock = {0}; static bool no_cons_log = false; +/* Kernel message buffer */ +static char kmsg[KBUF_SIZE]; +static size_t kmsg_i = 0; +static struct cdevsw kmsg_cdevw; + +static void +kmsg_append(const char *s, size_t len) +{ + spinlock_acquire(&kmsg_lock); + if ((kmsg_i + len) >= KBUF_SIZE) { + kmsg_i = 0; + } + + for (size_t i = 0; i < len; ++i) { + kmsg[kmsg_i + i] = s[i]; + } + kmsg_i += len; + spinlock_release(&kmsg_lock); +} + +/* + * Character device function. + */ +static int +kmsg_read(dev_t dev, struct sio_txn *sio, int flags) +{ + size_t len, offset, j; + size_t bytes_read = 0; + char *p = sio->buf; + + spinlock_acquire(&kmsg_lock); + len = sio->len; + offset = sio->offset; + + if (len == 0) { + spinlock_release(&kmsg_lock); + return -EINVAL; + } + if (offset >= kmsg_i) { + spinlock_release(&kmsg_lock); + return 0; + } + + for (size_t i = 0; i < len; ++i) { + j = offset + i; + if (j > kmsg_i) { + break; + } + + p[i] = kmsg[j]; + ++bytes_read; + } + + spinlock_release(&kmsg_lock); + return bytes_read; +} + static void syslog_write(const char *s, size_t len) { @@ -65,6 +133,8 @@ syslog_write(const char *s, size_t len) } } + kmsg_append(s, len); + /* * If the USER_KMSG option is disabled in kconf, * do not log to the console if everything else @@ -138,10 +208,31 @@ kprintf(const char *fmt, ...) * is already operating in a user context. * * XXX: This is ignored if the kconf USER_KMSG - * option is set to "no" + * option is set to "no". A kmsg device file + * is also created on the first call. */ void syslog_silence(bool option) { + static bool once = false; + static char devname[] = "kmsg"; + devmajor_t major; + dev_t dev; + + if (!once) { + once = true; + major = dev_alloc_major(); + dev = dev_alloc(major); + + dev_register(major, dev, &kmsg_cdevw); + devfs_create_entry(devname, major, dev, 0444); + + } + no_cons_log = option; } + +static struct cdevsw kmsg_cdevw = { + .read = kmsg_read, + .write = nowrite +}; |