diff options
Diffstat (limited to 'na/include')
| -rw-r--r-- | na/include/lume/klog.h | 167 | ||||
| -rw-r--r-- | na/include/lume/kprintf.h | 39 | ||||
| -rw-r--r-- | na/include/lume/panic.h | 16 | ||||
| -rw-r--r-- | na/include/lume/types.h | 5 |
4 files changed, 210 insertions, 17 deletions
diff --git a/na/include/lume/klog.h b/na/include/lume/klog.h new file mode 100644 index 0000000..457dcfe --- /dev/null +++ b/na/include/lume/klog.h @@ -0,0 +1,167 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* Copyright (C) 2026 Richard Qin */ + +#pragma once + +/* + * Kernel Logging Subsystem + * + * All kernel output goes through klog(), which formats messages into + * a fixed-size ring buffer and optionally emits them to the console. + * + * Architecture: + * vsnprintf_() ← pure formatting (mpaland/printf) + * ↓ + * KlogBuffer (ring) ← all messages stored here + * ↓ + * early_putc() (sync) ← current: synchronous UART output + * klogd thread (async) ← future: background flush thread + * /proc/kmsg ← future: userspace dmesg interface + * + * Reference: docs/specs/klog.md + */ + +#include <lume/types.h> + +/* ======================================================================== + * Log Levels (matches Linux kern_levels.h ordering) + * ======================================================================== */ + +enum KlogLevel : uint8 { + KLOG_EMERG = 0, /* System is unusable */ + KLOG_ALERT = 1, /* Action must be taken immediately */ + KLOG_CRIT = 2, /* Critical conditions */ + KLOG_ERR = 3, /* Error conditions */ + KLOG_WARN = 4, /* Warning conditions */ + KLOG_NOTICE = 5, /* Normal but significant condition */ + KLOG_INFO = 6, /* Informational */ + KLOG_DEBUG = 7, /* Debug-level messages */ +}; + +/* Log subsystems (bitmask-friendly) */ +enum KlogSubsys : uint8 { + KLOG_SUBSYS_GENERIC = 0, + KLOG_SUBSYS_SCHED = 1, + KLOG_SUBSYS_TRAP = 2, + KLOG_SUBSYS_IRQ = 3, + KLOG_SUBSYS_TIMER = 4, + KLOG_SUBSYS_VMM = 5, + KLOG_SUBSYS_PMM = 6, + KLOG_SUBSYS_SLAB = 7, + KLOG_SUBSYS_FS = 8, + KLOG_SUBSYS_DRIVER = 9, + KLOG_SUBSYS_TEST = 10, + KLOG_SUBSYS_MAX = 11, +}; + +/* Default: show everything up to INFO. DEBUG is compile-gated. */ +#ifndef KLOG_DEFAULT_LEVEL +#define KLOG_DEFAULT_LEVEL KLOG_INFO +#endif + +/* Ring buffer size: 2^KLOG_BUF_SHIFT bytes (default 64KB) */ +#ifndef KLOG_BUF_SHIFT +#define KLOG_BUF_SHIFT 16 +#endif + +#define KLOG_BUF_SIZE (1U << KLOG_BUF_SHIFT) + +/* Maximum length of a single log message (stack-allocated) */ +#define KLOG_LINE_MAX 256 + +struct KlogStats { + uint32 head; + uint32 tail; + uint32 console_tail; + uint32 dropped; + uint32 seq; +}; + +struct KlogRateLimit { + uint64 last_ts; + uint32 interval; + uint32 burst; + uint32 printed; + uint32 suppressed; +}; + +#ifdef __cplusplus +extern "C" { +#endif + +/* ======================================================================== + * Initialization + * ======================================================================== */ + +/* Initialize the ring buffer and console backend. Call once from BSP. */ +void klog_init(void); + +/* ======================================================================== + * Core API + * ======================================================================== */ + +/* Write a leveled log message. Formats into ring buffer, then + * synchronously flushes to console if level <= current threshold. */ +__attribute__((format(printf, 2, 3))) +void klog(KlogLevel level, const char* fmt, ...); + +__attribute__((format(printf, 3, 4))) +void klog_ex(KlogLevel level, KlogSubsys subsys, const char* fmt, ...); + +/* Set runtime log level filter. Messages above this level are + * still stored in the ring buffer but not printed to console. */ +void klog_set_level(KlogLevel level); + +void klog_set_subsys_mask(uint64 mask); +void klog_enable_subsys(KlogSubsys subsys); +void klog_disable_subsys(KlogSubsys subsys); + +/* ======================================================================== + * Ring Buffer Read (for future dmesg / /proc/kmsg) + * ======================================================================== */ + +/* Read up to 'size' bytes from the ring buffer into 'buf'. + * Returns number of bytes read. Non-destructive peek. */ +int klog_read(char* buf, int size); + +/* Read and consume entries (advances tail). */ +int klog_read_consume(char* buf, int size); + +/* Flush pending entries to console (advances console tail). */ +void klog_flush(void); + +bool klog_ratelimit(KlogRateLimit* rl, uint64 now); + +void klog_stats(KlogStats* out); + +/* ======================================================================== + * Convenience Macros + * ======================================================================== */ + +#define pr_emerg(fmt, ...) klog_ex(KLOG_EMERG, KLOG_SUBSYS_GENERIC, fmt, ##__VA_ARGS__) +#define pr_alert(fmt, ...) klog_ex(KLOG_ALERT, KLOG_SUBSYS_GENERIC, fmt, ##__VA_ARGS__) +#define pr_crit(fmt, ...) klog_ex(KLOG_CRIT, KLOG_SUBSYS_GENERIC, fmt, ##__VA_ARGS__) +#define pr_err(fmt, ...) klog_ex(KLOG_ERR, KLOG_SUBSYS_GENERIC, fmt, ##__VA_ARGS__) +#define pr_warn(fmt, ...) klog_ex(KLOG_WARN, KLOG_SUBSYS_GENERIC, fmt, ##__VA_ARGS__) +#define pr_notice(fmt, ...) klog_ex(KLOG_NOTICE, KLOG_SUBSYS_GENERIC, fmt, ##__VA_ARGS__) +#define pr_info(fmt, ...) klog_ex(KLOG_INFO, KLOG_SUBSYS_GENERIC, fmt, ##__VA_ARGS__) + +#define pr_emerg_s(subsys, fmt, ...) klog_ex(KLOG_EMERG, subsys, fmt, ##__VA_ARGS__) +#define pr_alert_s(subsys, fmt, ...) klog_ex(KLOG_ALERT, subsys, fmt, ##__VA_ARGS__) +#define pr_crit_s(subsys, fmt, ...) klog_ex(KLOG_CRIT, subsys, fmt, ##__VA_ARGS__) +#define pr_err_s(subsys, fmt, ...) klog_ex(KLOG_ERR, subsys, fmt, ##__VA_ARGS__) +#define pr_warn_s(subsys, fmt, ...) klog_ex(KLOG_WARN, subsys, fmt, ##__VA_ARGS__) +#define pr_notice_s(subsys, fmt, ...) klog_ex(KLOG_NOTICE, subsys, fmt, ##__VA_ARGS__) +#define pr_info_s(subsys, fmt, ...) klog_ex(KLOG_INFO, subsys, fmt, ##__VA_ARGS__) + +#ifdef KLOG_ENABLE_DEBUG +#define pr_debug(fmt, ...) klog_ex(KLOG_DEBUG, KLOG_SUBSYS_GENERIC, fmt, ##__VA_ARGS__) +#else +#define pr_debug(fmt, ...) do {} while (0) +#endif + +extern "C" [[noreturn]] void kernel_panic(const char* msg, const char* detail = nullptr); + +#ifdef __cplusplus +} +#endif diff --git a/na/include/lume/kprintf.h b/na/include/lume/kprintf.h new file mode 100644 index 0000000..b158602 --- /dev/null +++ b/na/include/lume/kprintf.h @@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* Copyright (C) 2026 Richard Qin */ + +#pragma once + +/* + * Kernel Formatted Output — kprintf + * + * Provides printf-style formatted output for the kernel. + * Built on top of stb_sprintf for full format string support + * without any libc dependency. + * + * Output is synchronous and directed to the console (UART). + * Safe to call from any context (interrupt or process). + * + * Usage: + * kprintf("Hello %s, addr=0x%lx\n", name, addr); + */ + +#include <stdarg.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* Formatted print to console (like printf). */ +__attribute__((format(printf, 1, 2))) +int kprintf(const char* fmt, ...); + +/* Formatted print with va_list. */ +int kvprintf(const char* fmt, va_list va); + +/* Formatted snprintf into buffer. */ +__attribute__((format(printf, 3, 4))) +int ksnprintf(char* buf, int count, const char* fmt, ...); + +#ifdef __cplusplus +} +#endif diff --git a/na/include/lume/panic.h b/na/include/lume/panic.h deleted file mode 100644 index 6316c28..0000000 --- a/na/include/lume/panic.h +++ /dev/null @@ -1,16 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* Copyright (C) 2026 Richard Qin */ - -#pragma once - -/* - * Kernel Panic — fatal error handler. - * - * Prints the message (if UART is ready), disables interrupts, - * and enters an infinite wfi loop. Never returns. - * - * Implementation will be provided by lib/kprintf.cc or a - * dedicated panic module. For now this header declares the interface. - */ - -extern "C" [[noreturn]] void kernel_panic(const char* msg, const char* detail = nullptr); diff --git a/na/include/lume/types.h b/na/include/lume/types.h index e296649..1d5b896 100644 --- a/na/include/lume/types.h +++ b/na/include/lume/types.h @@ -22,10 +22,13 @@ using int16 = signed short; using int32 = signed int; using int64 = signed long long; -using size_t = uint64; +typedef __SIZE_TYPE__ size_t; +typedef __PTRDIFF_TYPE__ ptrdiff_t; using ssize_t = int64; using uintptr = uint64; +#define offsetof(TYPE, MEMBER) __builtin_offsetof(TYPE, MEMBER) + /* Null pointer constant */ #ifndef nullptr /* C++11 and later have nullptr built-in */ |
