summaryrefslogtreecommitdiff
path: root/na/lib
diff options
context:
space:
mode:
authorRichard Qin <richard.qin.x@gmail.com>2026-07-10 11:24:56 +0800
committerRichard Qin <richard.qin.x@gmail.com>2026-07-10 11:24:56 +0800
commit1767d390fbf3d0c65389de46caf0b6d43ef3b6ad (patch)
tree0f5e01cd7c7a05abb6b1c7472d7f00f49caf02cc /na/lib
parent63dc025705f6533b91fb1a7d26e6ed864efd9900 (diff)
downloadlume-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.cc77
-rw-r--r--na/lib/fdt.c2
-rw-r--r--na/lib/fdt_addresses.c2
-rw-r--r--na/lib/fdt_empty_tree.c2
-rw-r--r--na/lib/fdt_ro.c2
-rw-r--r--na/lib/fdt_rw.c2
-rw-r--r--na/lib/fdt_strerror.c2
-rw-r--r--na/lib/fdt_sw.c2
-rw-r--r--na/lib/fdt_wip.c2
-rw-r--r--na/lib/klog.cc20
-rw-r--r--na/lib/kobject.cc82
-rw-r--r--na/lib/kprintf.cc41
-rw-r--r--na/lib/module.mk27
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