From b65829c94f64a798f18894c9c0dfc446a7806e07 Mon Sep 17 00:00:00 2001 From: Leonmmcoset Date: Sat, 11 Apr 2026 21:38:40 +0800 Subject: [PATCH] Stage 23 --- CMakeLists.txt | 13 ++++++++++-- clks/kernel/kmain.c | 2 +- clks/kernel/shell.c | 10 +++++++++ clks/lib/libc_compat.c | 32 ++++++++++++++++++++++++++++ clks/rust/src/lib.rs | 27 ++++++++++++++++++++++++ docs/README.md | 1 + docs/stage23.md | 47 ++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 129 insertions(+), 3 deletions(-) create mode 100644 clks/lib/libc_compat.c create mode 100644 clks/rust/src/lib.rs create mode 100644 docs/stage23.md diff --git a/CMakeLists.txt b/CMakeLists.txt index 0518c76..fe294f0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -93,6 +93,7 @@ set(USER_OBJ_ROOT "${USER_BUILD_ROOT}/obj") set(USER_APP_DIR "${USER_BUILD_ROOT}/apps") set(USER_LIB_DIR "${USER_BUILD_ROOT}/lib") set(USER_RUST_LIB "${USER_LIB_DIR}/libcleonos_user_rust.a") +set(KERNEL_RUST_LIB "${BUILD_ROOT}/libclks_kernel_rust.a") resolve_tool_with_fallback(CC gcc cc clang) resolve_tool_with_fallback(LD ld.lld ld) @@ -299,11 +300,19 @@ foreach(SRC IN LISTS ASM_SOURCES) add_kernel_asm_object("${SRC}" KERNEL_OBJECTS) endforeach() +add_custom_command( + OUTPUT "${KERNEL_RUST_LIB}" + COMMAND ${CMAKE_COMMAND} -E make_directory "${BUILD_ROOT}" + COMMAND ${RUSTC} --crate-type staticlib -C panic=abort -O "${CMAKE_SOURCE_DIR}/clks/rust/src/lib.rs" -o "${KERNEL_RUST_LIB}" + DEPENDS "${CMAKE_SOURCE_DIR}/clks/rust/src/lib.rs" + VERBATIM +) + add_custom_command( OUTPUT "${KERNEL_ELF}" COMMAND ${CMAKE_COMMAND} -E make_directory "${BUILD_ROOT}" - COMMAND ${LD} ${LDFLAGS_COMMON} -T "${LINKER_SCRIPT}" -o "${KERNEL_ELF}" ${KERNEL_OBJECTS} - DEPENDS ${KERNEL_OBJECTS} "${LINKER_SCRIPT}" + COMMAND ${LD} ${LDFLAGS_COMMON} -T "${LINKER_SCRIPT}" -o "${KERNEL_ELF}" ${KERNEL_OBJECTS} "${KERNEL_RUST_LIB}" + DEPENDS ${KERNEL_OBJECTS} "${LINKER_SCRIPT}" "${KERNEL_RUST_LIB}" "${CMAKE_SOURCE_DIR}/clks/rust/src/lib.rs" VERBATIM ) diff --git a/clks/kernel/kmain.c b/clks/kernel/kmain.c index 5b99ec1..4a04587 100644 --- a/clks/kernel/kmain.c +++ b/clks/kernel/kmain.c @@ -96,7 +96,7 @@ void clks_kernel_main(void) { clks_tty_init(); } - clks_log(CLKS_LOG_INFO, "BOOT", "CLEONOS Stage22 START"); + clks_log(CLKS_LOG_INFO, "BOOT", "CLEONOS Stage23 START"); if (boot_fb == CLKS_NULL) { clks_log(CLKS_LOG_WARN, "VIDEO", "NO FRAMEBUFFER FROM LIMINE"); diff --git a/clks/kernel/shell.c b/clks/kernel/shell.c index 8c202ad..7aaf927 100644 --- a/clks/kernel/shell.c +++ b/clks/kernel/shell.c @@ -42,6 +42,8 @@ static u64 clks_shell_cmd_ok = 0ULL; static u64 clks_shell_cmd_fail = 0ULL; static u64 clks_shell_cmd_unknown = 0ULL; +extern void clks_rusttest_hello(void); + static clks_bool clks_shell_is_space(char ch) { return (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n') ? CLKS_TRUE : CLKS_FALSE; } @@ -693,6 +695,7 @@ static clks_bool clks_shell_cmd_help(void) { clks_shell_writeln(" memstat / fsstat / taskstat"); clks_shell_writeln(" dmesg [n]"); clks_shell_writeln(" shstat"); + clks_shell_writeln(" rusttest"); clks_shell_writeln(" exec "); clks_shell_writeln(" clear"); clks_shell_writeln(" kbdstat"); @@ -1201,6 +1204,11 @@ static clks_bool clks_shell_cmd_shstat(void) { return CLKS_TRUE; } +static clks_bool clks_shell_cmd_rusttest(void) { + clks_rusttest_hello(); + return CLKS_TRUE; +} + static void clks_shell_execute_line(const char *line) { char line_buf[CLKS_SHELL_LINE_MAX]; char cmd[CLKS_SHELL_CMD_MAX]; @@ -1261,6 +1269,8 @@ static void clks_shell_execute_line(const char *line) { success = clks_shell_cmd_dmesg(arg); } else if (clks_shell_streq(cmd, "shstat") == CLKS_TRUE) { success = clks_shell_cmd_shstat(); + } else if (clks_shell_streq(cmd, "rusttest") == CLKS_TRUE) { + success = clks_shell_cmd_rusttest(); } else if (clks_shell_streq(cmd, "exec") == CLKS_TRUE || clks_shell_streq(cmd, "run") == CLKS_TRUE) { success = clks_shell_cmd_exec(arg); } else if (clks_shell_streq(cmd, "clear") == CLKS_TRUE) { diff --git a/clks/lib/libc_compat.c b/clks/lib/libc_compat.c new file mode 100644 index 0000000..7ecc9a0 --- /dev/null +++ b/clks/lib/libc_compat.c @@ -0,0 +1,32 @@ +#include +#include + +void *memcpy(void *dst, const void *src, usize count) { + return clks_memcpy(dst, src, count); +} + +void *memmove(void *dst, const void *src, usize count) { + return clks_memmove(dst, src, count); +} + +void *memset(void *dst, int value, usize count) { + return clks_memset(dst, value, count); +} + +int memcmp(const void *left, const void *right, usize count) { + const u8 *a = (const u8 *)left; + const u8 *b = (const u8 *)right; + usize i; + + for (i = 0U; i < count; i++) { + if (a[i] != b[i]) { + return (a[i] < b[i]) ? -1 : 1; + } + } + + return 0; +} + +int bcmp(const void *left, const void *right, usize count) { + return memcmp(left, right, count); +} \ No newline at end of file diff --git a/clks/rust/src/lib.rs b/clks/rust/src/lib.rs new file mode 100644 index 0000000..c437b3c --- /dev/null +++ b/clks/rust/src/lib.rs @@ -0,0 +1,27 @@ +#![no_std] + +use core::hint::spin_loop; +use core::panic::PanicInfo; + +extern "C" { + fn clks_tty_write(text: *const i8); +} + +const RUSTTEST_TEXT: &[u8] = b"Hello world!\n\0"; + +#[no_mangle] +pub extern "C" fn clks_rusttest_hello() { + unsafe { + clks_tty_write(RUSTTEST_TEXT.as_ptr() as *const i8); + } +} + +#[panic_handler] +fn panic(_info: &PanicInfo) -> ! { + loop { + spin_loop(); + } +} + +#[no_mangle] +pub extern "C" fn rust_eh_personality() {} \ No newline at end of file diff --git a/docs/README.md b/docs/README.md index 8f7dee6..6234d3c 100644 --- a/docs/README.md +++ b/docs/README.md @@ -19,6 +19,7 @@ - `stage20.md` - `stage21.md` - `stage22.md` +- `stage23.md` ## Notes - Stage docs use a fixed template: goal, implementation, acceptance criteria, build targets, QEMU command, and debugging notes. diff --git a/docs/stage23.md b/docs/stage23.md new file mode 100644 index 0000000..7684b81 --- /dev/null +++ b/docs/stage23.md @@ -0,0 +1,47 @@ +# CLeonOS Stage23 + +## Stage Goal +- Add a kernel shell command `rusttest`. +- Implement `rusttest` logic in Rust (`no_std`) instead of C. +- Link Rust object into the kernel ELF so command runs in kernel mode. + +## What Was Implemented +- Kernel Rust source added: + - `clks/rust/src/lib.rs` + - exports `clks_rusttest_hello()` + - output text: `Hello world!` +- Kernel build integration (CMake): + - build `libclks_kernel_rust.a` + - link kernel ELF with `${KERNEL_RUST_LIB}` +- Shell integration: + - add command `rusttest` + - `rusttest` calls Rust symbol `clks_rusttest_hello()` +- Compatibility symbols for Rust link: + - add `clks/lib/libc_compat.c` for `memcpy/memset/memmove/memcmp/bcmp` +- Stage banner updated: + - `CLEONOS Stage23 START` + +## Acceptance Criteria +- Kernel boots and prints `CLEONOS Stage23 START`. +- `help` contains `rusttest`. +- Running `rusttest` prints exactly: + - `Hello world!` +- No regression to existing shell commands. + +## Build Targets +- `make setup` +- `make userapps` +- `make iso` +- `make run` +- `make debug` + +## QEMU Command +- `qemu-system-x86_64 -M q35 -m 1024M -cdrom build/CLeonOS-x86_64.iso -serial stdio` + +## Common Bugs and Debugging +- Rust link undefined symbols (`memcpy/memset/...`): + - Ensure `clks/lib/libc_compat.c` is included in kernel source set. +- Panic-related undefined symbol: + - Ensure Rust file keeps `#[panic_handler]` and `rust_eh_personality` stub. +- `rusttest` command not found: + - Confirm `help` output includes `rusttest` and shell dispatch branch exists. \ No newline at end of file