diff options
| author | Richard Qin <richard.qin.x@gmail.com> | 2026-07-10 11:24:56 +0800 |
|---|---|---|
| committer | Richard Qin <richard.qin.x@gmail.com> | 2026-07-10 11:24:56 +0800 |
| commit | 1767d390fbf3d0c65389de46caf0b6d43ef3b6ad (patch) | |
| tree | 0f5e01cd7c7a05abb6b1c7472d7f00f49caf02cc /na/lib | |
| parent | 63dc025705f6533b91fb1a7d26e6ed864efd9900 (diff) | |
| download | lume-1767d390fbf3d0c65389de46caf0b6d43ef3b6ad.tar.gz lume-1767d390fbf3d0c65389de46caf0b6d43ef3b6ad.tar.xz | |
feat: establish bootable new architecture checkpoint
Replace the compressed boot path with a relocatable higher-half RISC-V entry, expand memory and SMP support, and add the driver, TTY, VFS, exec, signal, syscall, initramfs, and self-test infrastructure needed for a bootable kernel checkpoint.
Diffstat (limited to 'na/lib')
| -rw-r--r-- | na/lib/decompress_lz4.cc | 77 | ||||
| -rw-r--r-- | na/lib/fdt.c | 2 | ||||
| -rw-r--r-- | na/lib/fdt_addresses.c | 2 | ||||
| -rw-r--r-- | na/lib/fdt_empty_tree.c | 2 | ||||
| -rw-r--r-- | na/lib/fdt_ro.c | 2 | ||||
| -rw-r--r-- | na/lib/fdt_rw.c | 2 | ||||
| -rw-r--r-- | na/lib/fdt_strerror.c | 2 | ||||
| -rw-r--r-- | na/lib/fdt_sw.c | 2 | ||||
| -rw-r--r-- | na/lib/fdt_wip.c | 2 | ||||
| -rw-r--r-- | na/lib/klog.cc | 20 | ||||
| -rw-r--r-- | na/lib/kobject.cc | 82 | ||||
| -rw-r--r-- | na/lib/kprintf.cc | 41 | ||||
| -rw-r--r-- | na/lib/module.mk | 27 |
13 files changed, 169 insertions, 94 deletions
diff --git a/na/lib/decompress_lz4.cc b/na/lib/decompress_lz4.cc deleted file mode 100644 index 6a93936..0000000 --- a/na/lib/decompress_lz4.cc +++ /dev/null @@ -1,77 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* Copyright (C) 2026 Richard Qin */ - -#include <lume/decompress.h> - -int lz4_decompress(const uint8* src, uint32 src_len, uint8* dst, uint32 dst_cap) -{ - const uint8* ip = src; - const uint8* iend = src + src_len; - uint8* op = dst; - uint8* oend = dst + dst_cap; - - while (ip < iend) { - uint8 token = *ip++; - uint32 lit_len = token >> 4; - - if (lit_len == 15) { - uint8 s = 0; - do { - if (ip >= iend) { - return -1; - } - s = *ip++; - lit_len += s; - } while (s == 255); - } - - if (ip + lit_len > iend) { - return -1; - } - if (op + lit_len > oend) { - return -1; - } - - for (uint32 i = 0; i < lit_len; ++i) { - *op++ = *ip++; - } - - if (ip >= iend) { - break; - } - if (ip + 2 > iend) { - return -1; - } - - uint32 off = static_cast<uint32>(ip[0]) | (static_cast<uint32>(ip[1]) << 8); - ip += 2; - if (off == 0 || off > static_cast<uint32>(op - dst)) { - return -1; - } - - uint32 match_len = token & 0x0F; - if (match_len == 15) { - uint8 s = 0; - do { - if (ip >= iend) { - return -1; - } - s = *ip++; - match_len += s; - } while (s == 255); - } - match_len += 4; - - if (op + match_len > oend) { - return -1; - } - - uint8* match = op - off; - for (uint32 i = 0; i < match_len; ++i) { - op[i] = match[i]; - } - op += match_len; - } - - return static_cast<int>(op - dst); -} diff --git a/na/lib/fdt.c b/na/lib/fdt.c new file mode 100644 index 0000000..1b20383 --- /dev/null +++ b/na/lib/fdt.c @@ -0,0 +1,2 @@ +#include <lume/libfdt_env.h> +#include "../scripts/dtc/libfdt/fdt.c" diff --git a/na/lib/fdt_addresses.c b/na/lib/fdt_addresses.c new file mode 100644 index 0000000..d58f896 --- /dev/null +++ b/na/lib/fdt_addresses.c @@ -0,0 +1,2 @@ +#include <lume/libfdt_env.h> +#include "../scripts/dtc/libfdt/fdt_addresses.c" diff --git a/na/lib/fdt_empty_tree.c b/na/lib/fdt_empty_tree.c new file mode 100644 index 0000000..37f8ef8 --- /dev/null +++ b/na/lib/fdt_empty_tree.c @@ -0,0 +1,2 @@ +#include <lume/libfdt_env.h> +#include "../scripts/dtc/libfdt/fdt_empty_tree.c" diff --git a/na/lib/fdt_ro.c b/na/lib/fdt_ro.c new file mode 100644 index 0000000..3599d49 --- /dev/null +++ b/na/lib/fdt_ro.c @@ -0,0 +1,2 @@ +#include <lume/libfdt_env.h> +#include "../scripts/dtc/libfdt/fdt_ro.c" diff --git a/na/lib/fdt_rw.c b/na/lib/fdt_rw.c new file mode 100644 index 0000000..65d7a71 --- /dev/null +++ b/na/lib/fdt_rw.c @@ -0,0 +1,2 @@ +#include <lume/libfdt_env.h> +#include "../scripts/dtc/libfdt/fdt_rw.c" diff --git a/na/lib/fdt_strerror.c b/na/lib/fdt_strerror.c new file mode 100644 index 0000000..dae35ea --- /dev/null +++ b/na/lib/fdt_strerror.c @@ -0,0 +1,2 @@ +#include <lume/libfdt_env.h> +#include "../scripts/dtc/libfdt/fdt_strerror.c" diff --git a/na/lib/fdt_sw.c b/na/lib/fdt_sw.c new file mode 100644 index 0000000..d04f220 --- /dev/null +++ b/na/lib/fdt_sw.c @@ -0,0 +1,2 @@ +#include <lume/libfdt_env.h> +#include "../scripts/dtc/libfdt/fdt_sw.c" diff --git a/na/lib/fdt_wip.c b/na/lib/fdt_wip.c new file mode 100644 index 0000000..ebfb3c1 --- /dev/null +++ b/na/lib/fdt_wip.c @@ -0,0 +1,2 @@ +#include <lume/libfdt_env.h> +#include "../scripts/dtc/libfdt/fdt_wip.c" diff --git a/na/lib/klog.cc b/na/lib/klog.cc index bf081de..86c67f8 100644 --- a/na/lib/klog.cc +++ b/na/lib/klog.cc @@ -166,9 +166,7 @@ static void ring_drop_oldest(uint32 needed) static void console_emit(const char* s, int len) { - for (int i = 0; i < len; ++i) { - early_putc(s[i]); - } + console_write_all(s, len); } static int klog_format_line(char* out, int out_size, @@ -329,12 +327,20 @@ static void klog_vex(KlogLevel level, KlogSubsys subsys, ring_write_bytes(msg, hdr.len); if (do_console) { g_klog.console_tail = g_klog.head; + /* Emit to UART while holding the lock to prevent + * interleaved output from concurrent CPUs. */ + char line[KLOG_LINE_MAX + 64]; + int line_len = klog_format_line(line, sizeof(line), + hdr, msg, hdr.len); + if (line_len > 0) { + console_emit(line, line_len); + } } - } - - if (do_console) { + } else if (do_console) { + /* Pre-init or panic mode: emit without lock */ char line[KLOG_LINE_MAX + 64]; - int line_len = klog_format_line(line, sizeof(line), hdr, msg, hdr.len); + int line_len = klog_format_line(line, sizeof(line), + hdr, msg, hdr.len); if (line_len > 0) { console_emit(line, line_len); } diff --git a/na/lib/kobject.cc b/na/lib/kobject.cc new file mode 100644 index 0000000..8e8329e --- /dev/null +++ b/na/lib/kobject.cc @@ -0,0 +1,82 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* Copyright (C) 2026 Richard Qin */ + +/* + * kobject — implementation. + * + * Lives in lib/ (mirroring Linux's lib/kobject.c) because kobject is a + * generic primitive, not tied to the driver model. + * + * Reference: docs/specs/storage_stack.md §4.2 + */ + +#include <lume/kobject.h> +#include <lume/container_of.h> +#include <lume/klog.h> + +void kobject_init(kobject* k, const kobj_type* type) +{ + if (k == nullptr) { + return; + } + k->name = nullptr; + k->parent = nullptr; + k->ktype = type; + k->state_in_sysfs = false; + k->entry.init(); + k->children.init(); + k->lock.init("kobject"); + kref_init(&k->refcount); +} + +int kobject_add(kobject* k, kobject* parent, const char* name) +{ + if (k == nullptr) { + return -1; + } + k->name = name; + if (parent != nullptr) { + kobject_get(parent); + k->parent = parent; + LockGuard g(parent->lock); + list_add_tail(&k->entry, &parent->children); + } + return 0; +} + +void kobject_del(kobject* k) +{ + if (k == nullptr || k->parent == nullptr) { + return; + } + kobject* parent = k->parent; + { + LockGuard g(parent->lock); + list_del_init(&k->entry); + } + k->parent = nullptr; + kobject_put(parent); +} + +void kobject_get(kobject* k) +{ + if (k != nullptr) { + kref_get(&k->refcount); + } +} + +static void kobject_release(kref* r) +{ + kobject* k = container_of(r, kobject, refcount); + if (k->ktype != nullptr && k->ktype->release != nullptr) { + k->ktype->release(k); + } +} + +void kobject_put(kobject* k) +{ + if (k == nullptr) { + return; + } + kref_put(&k->refcount, kobject_release); +} diff --git a/na/lib/kprintf.cc b/na/lib/kprintf.cc index ddd2e59..a98de71 100644 --- a/na/lib/kprintf.cc +++ b/na/lib/kprintf.cc @@ -5,21 +5,44 @@ * kprintf.cc — Kernel formatted output * * Uses mpaland/printf's vsnprintf_ as the core formatting engine. - * All kernel output ultimately goes through this module. * * Architecture: * vsnprintf_() ← pure formatting, writes to buffer * ↓ - * kprintf() ← format + emit to UART via early_putc + * kprintf() ← format + emit via console_write_all() * kvprintf() ← va_list variant * ksnprintf() ← format into caller's buffer + * + * Output path: + * Pre-registration: console_write_all() → early_putc() fallback + * Post-registration: console_write_all() → struct console chain */ #include <lume/kprintf.h> #include <lume/console.h> +#include <lume/atomic.h> +#include <arch/cpu.h> #include "printf.h" /* ------------------------------------------------------------------ */ +/* Console spinlock (raw, no scheduler dependency — safe in panic) */ +/* ------------------------------------------------------------------ */ + +static lume::atomic<uint32> g_console_lock{0}; + +static inline void console_lock_acquire() +{ + while (g_console_lock.exchange(1, __ATOMIC_ACQUIRE) != 0) { + /* spin */ + } +} + +static inline void console_lock_release() +{ + g_console_lock.store(0, __ATOMIC_RELEASE); +} + +/* ------------------------------------------------------------------ */ /* _putchar: required by mpaland/printf for printf_() / vprintf_() */ /* ------------------------------------------------------------------ */ @@ -40,10 +63,10 @@ extern "C" int kprintf(const char* fmt, ...) int len = vsnprintf_(buf, sizeof(buf), fmt, va); va_end(va); - /* Emit to console */ - for (int i = 0; i < len && buf[i] != '\0'; ++i) { - early_putc(buf[i]); - } + /* Emit to console under lock */ + console_lock_acquire(); + console_write_all(buf, len); + console_lock_release(); return len; } @@ -52,9 +75,9 @@ extern "C" int kvprintf(const char* fmt, va_list va) char buf[256]; int len = vsnprintf_(buf, sizeof(buf), fmt, va); - for (int i = 0; i < len && buf[i] != '\0'; ++i) { - early_putc(buf[i]); - } + console_lock_acquire(); + console_write_all(buf, len); + console_lock_release(); return len; } diff --git a/na/lib/module.mk b/na/lib/module.mk index 2cfadf7..0b178f8 100644 --- a/na/lib/module.mk +++ b/na/lib/module.mk @@ -1,10 +1,10 @@ # lib/module.mk SRCS_CC += lib/cxx_abi.cc SRCS_CC += lib/rbtree.cc +SRCS_CC += lib/kobject.cc SRCS_CC += lib/kprintf.cc SRCS_CC += lib/klog.cc SRCS_CC += lib/random.cc -SRCS_CC += lib/decompress_lz4.cc SRCS_C += lib/printf.c # ============================================================ @@ -39,3 +39,28 @@ MUSL_C_SRCS := $(filter-out $(MUSL_EXCLUDED_C),$(MUSL_ALL_C)) SRCS_C += $(MUSL_C_SRCS) SRCS_S += $(filter %.S,$(MUSL_ASM_SRCS)) SRCS_s += $(filter %.s,$(MUSL_ASM_SRCS)) + +# ============================================================ +# libfdt — kernel adapter shims around scripts/dtc/libfdt/. +# +# Each shim is two lines: +# #include <linux/libfdt_env.h> +# #include "../scripts/dtc/libfdt/fdt*.c" +# matching Linux lib/fdt*.c verbatim. The compile recipe needs: +# - <linux/libfdt_env.h> reachable via the default -Iinclude path +# - -I scripts/dtc/libfdt so the upstream source's #include <libfdt.h> +# and friends resolve to scripts/dtc/libfdt/libfdt.h +# Overriding CFLAGS_LIBC (which the %.o: %.c rule uses) avoids dragging +# in libc-shim headers — libfdt is freestanding-compatible and uses +# only the string functions forward-declared in <linux/libfdt_env.h>. +# ============================================================ +LIBFDT_FILES := fdt.c fdt_ro.c fdt_wip.c fdt_rw.c fdt_sw.c \ + fdt_strerror.c fdt_empty_tree.c fdt_addresses.c +SRCS_C += $(addprefix lib/,$(LIBFDT_FILES)) + +# Per-target CFLAGS override: plain CFLAGS plus the upstream include dir. +# Use `=` (recursive) not `:=` because $(CFLAGS) is defined in the top +# Makefile AFTER this file is included — `:=` would expand it now (empty) +# and lose -Iinclude, breaking <linux/libfdt_env.h>. +$(addprefix $(BUILD)/lib/,$(LIBFDT_FILES:.c=.o)): CFLAGS_LIBC = \ + $(CFLAGS) -I scripts/dtc/libfdt |
