From e5ff77ccb4319036ff1e03ae30ac16d145a99d46 Mon Sep 17 00:00:00 2001 From: Leonmmcoset Date: Tue, 21 Apr 2026 22:48:27 +0800 Subject: [PATCH] =?UTF-8?q?=E7=89=88=E6=9C=AC=E5=8F=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CMakeLists.txt | 4 ++++ cleonos/c/apps/fastfetch_main.c | 7 ++++++ cleonos/c/include/cleonos_syscall.h | 2 ++ cleonos/c/src/syscall.c | 4 ++++ clks/include/clks/syscall.h | 1 + clks/kernel/runtime/syscall.c | 10 ++++++++- common/include/cleonos_version.h | 7 ++++++ docs/syscall.md | 15 +++++++++++-- wine/README.md | 8 ++++++- .../__pycache__/constants.cpython-313.pyc | Bin 4020 -> 4232 bytes .../__pycache__/runner.cpython-313.pyc | Bin 103432 -> 104209 bytes wine/cleonos_wine_lib/constants.py | 7 ++++++ wine/cleonos_wine_lib/runner.py | 21 ++++++++++++++++++ 13 files changed, 82 insertions(+), 4 deletions(-) create mode 100644 common/include/cleonos_version.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 6ae5e08..9d5651b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -265,6 +265,7 @@ set(CFLAGS_COMMON -Wextra -Werror "-I${CMAKE_SOURCE_DIR}/clks/include" + "-I${CMAKE_SOURCE_DIR}/common/include" ) set(CXXFLAGS_COMMON @@ -281,6 +282,7 @@ set(CXXFLAGS_COMMON -Wextra -Werror "-I${CMAKE_SOURCE_DIR}/clks/include" + "-I${CMAKE_SOURCE_DIR}/common/include" ) set(ARCH_CFLAGS @@ -357,6 +359,7 @@ set(USER_CFLAGS -Wextra -Werror "-I${CMAKE_SOURCE_DIR}/cleonos/c/include" + "-I${CMAKE_SOURCE_DIR}/common/include" ) set(USER_CFLAGS_DOOM @@ -372,6 +375,7 @@ set(USER_CFLAGS_DOOM -Wno-sign-compare -D_DEFAULT_SOURCE -D_POSIX_C_SOURCE=200809L + "-I${CMAKE_SOURCE_DIR}/common/include" "-I${CMAKE_SOURCE_DIR}/cleonos/third-party/doomgeneric/doomgeneric" "-include" "${CMAKE_SOURCE_DIR}/cleonos/c/apps/doom/doom_shim.h" diff --git a/cleonos/c/apps/fastfetch_main.c b/cleonos/c/apps/fastfetch_main.c index 9db73d2..43d8b5b 100644 --- a/cleonos/c/apps/fastfetch_main.c +++ b/cleonos/c/apps/fastfetch_main.c @@ -1,4 +1,5 @@ #include "cmd_runtime.h" +#include static u64 ush_fastfetch_u64_to_dec(char *out, u64 out_size, u64 value) { char rev[32]; u64 digits = 0ULL; @@ -115,6 +116,7 @@ static int ush_cmd_fastfetch(const char *arg) { u64 tty_count; u64 exec_req; u64 exec_ok; + char kernel_version[32]; if (arg != (const char *)0 && arg[0] != '\0') { if (ush_streq(arg, "--plain") != 0) { @@ -132,12 +134,17 @@ static int ush_cmd_fastfetch(const char *arg) { tty_count = cleonos_sys_tty_count(); exec_req = cleonos_sys_exec_request_count(); exec_ok = cleonos_sys_exec_success_count(); + if (cleonos_sys_kernel_version(kernel_version, (u64)sizeof(kernel_version)) == 0ULL) { + ush_copy(kernel_version, (u64)sizeof(kernel_version), "unknown"); + } ush_fastfetch_print_logo(plain); ush_write_char('\n'); ush_fastfetch_print_text(plain, "OS", "CLeonOS x86_64"); ush_fastfetch_print_text(plain, "Shell", "User Shell (/shell/shell.elf)"); + ush_fastfetch_print_text(plain, "CLeonOSVersion", CLEONOS_VERSION_STRING); + ush_fastfetch_print_text(plain, "CLKSVersion", kernel_version); ush_fastfetch_print_u64(plain, "PID", cleonos_sys_getpid()); ush_fastfetch_print_u64(plain, "UptimeTicks", cleonos_sys_timer_ticks()); ush_fastfetch_print_u64(plain, "Tasks", cleonos_sys_task_count()); diff --git a/cleonos/c/include/cleonos_syscall.h b/cleonos/c/include/cleonos_syscall.h index 7d096d4..6c942e7 100644 --- a/cleonos/c/include/cleonos_syscall.h +++ b/cleonos/c/include/cleonos_syscall.h @@ -144,6 +144,7 @@ typedef struct cleonos_fb_blit_req { #define CLEONOS_SYSCALL_FB_INFO 81ULL #define CLEONOS_SYSCALL_FB_BLIT 82ULL #define CLEONOS_SYSCALL_FB_CLEAR 83ULL +#define CLEONOS_SYSCALL_KERNEL_VERSION 84ULL u64 cleonos_syscall(u64 id, u64 arg0, u64 arg1, u64 arg2); u64 cleonos_sys_log_write(const char *message, u64 length); @@ -230,5 +231,6 @@ u64 cleonos_sys_dl_sym(u64 handle, const char *symbol); u64 cleonos_sys_fb_info(cleonos_fb_info *out_info); u64 cleonos_sys_fb_blit(const cleonos_fb_blit_req *req); u64 cleonos_sys_fb_clear(u64 rgb); +u64 cleonos_sys_kernel_version(char *out_version, u64 out_size); #endif diff --git a/cleonos/c/src/syscall.c b/cleonos/c/src/syscall.c index 1ea4ba1..3286323 100644 --- a/cleonos/c/src/syscall.c +++ b/cleonos/c/src/syscall.c @@ -367,3 +367,7 @@ u64 cleonos_sys_fb_blit(const cleonos_fb_blit_req *req) { u64 cleonos_sys_fb_clear(u64 rgb) { return cleonos_syscall(CLEONOS_SYSCALL_FB_CLEAR, rgb, 0ULL, 0ULL); } + +u64 cleonos_sys_kernel_version(char *out_version, u64 out_size) { + return cleonos_syscall(CLEONOS_SYSCALL_KERNEL_VERSION, (u64)out_version, out_size, 0ULL); +} diff --git a/clks/include/clks/syscall.h b/clks/include/clks/syscall.h index a2869ce..8bfb8e4 100644 --- a/clks/include/clks/syscall.h +++ b/clks/include/clks/syscall.h @@ -87,6 +87,7 @@ #define CLKS_SYSCALL_FB_INFO 81ULL #define CLKS_SYSCALL_FB_BLIT 82ULL #define CLKS_SYSCALL_FB_CLEAR 83ULL +#define CLKS_SYSCALL_KERNEL_VERSION 84ULL void clks_syscall_init(void); u64 clks_syscall_dispatch(void *frame_ptr); diff --git a/clks/kernel/runtime/syscall.c b/clks/kernel/runtime/syscall.c index 901b434..cec03e9 100644 --- a/clks/kernel/runtime/syscall.c +++ b/clks/kernel/runtime/syscall.c @@ -16,6 +16,7 @@ #include #include #include +#include #define CLKS_SYSCALL_LOG_MAX_LEN 191U #define CLKS_SYSCALL_PATH_MAX 192U @@ -33,7 +34,7 @@ #define CLKS_SYSCALL_KDBG_STACK_WINDOW_BYTES (128ULL * 1024ULL) #define CLKS_SYSCALL_KERNEL_SYMBOL_FILE "/system/kernel.sym" #define CLKS_SYSCALL_KERNEL_ADDR_BASE 0xFFFF800000000000ULL -#define CLKS_SYSCALL_STATS_MAX_ID CLKS_SYSCALL_FB_CLEAR +#define CLKS_SYSCALL_STATS_MAX_ID CLKS_SYSCALL_KERNEL_VERSION #define CLKS_SYSCALL_STATS_RING_SIZE 256U #define CLKS_SYSCALL_USC_MAX_ALLOWED_APPS 64U @@ -467,6 +468,11 @@ static u64 clks_syscall_fb_blit(u64 arg0) { return 1ULL; } +static u64 clks_syscall_kernel_version(u64 arg0, u64 arg1) { + usize len = clks_strlen(CLKS_VERSION_STRING); + return clks_syscall_copy_text_to_user(arg0, arg1, CLKS_VERSION_STRING, len); +} + static u64 clks_syscall_fd_open(u64 arg0, u64 arg1, u64 arg2) { char path[CLKS_SYSCALL_PATH_MAX]; @@ -2513,6 +2519,8 @@ u64 clks_syscall_dispatch(void *frame_ptr) { return clks_syscall_fb_blit(frame->rbx); case CLKS_SYSCALL_FB_CLEAR: return clks_syscall_fb_clear(frame->rbx); + case CLKS_SYSCALL_KERNEL_VERSION: + return clks_syscall_kernel_version(frame->rbx, frame->rcx); default: return (u64)-1; } diff --git a/common/include/cleonos_version.h b/common/include/cleonos_version.h new file mode 100644 index 0000000..6186e5c --- /dev/null +++ b/common/include/cleonos_version.h @@ -0,0 +1,7 @@ +#ifndef CLEONOS_VERSION_H +#define CLEONOS_VERSION_H + +#define CLKS_VERSION_STRING "1.0.0-alpha" +#define CLEONOS_VERSION_STRING "1.0.0-alpha" + +#endif diff --git a/docs/syscall.md b/docs/syscall.md index 32a1a85..786c54c 100644 --- a/docs/syscall.md +++ b/docs/syscall.md @@ -83,7 +83,7 @@ u64 cleonos_syscall(u64 id, u64 arg0, u64 arg1, u64 arg2); - `/proc/`:指定 PID 快照文本 - `/proc` 为只读;写入类 syscall 不支持。 -## 4. Syscall 列表(0~83) +## 4. Syscall 列表(0~84) ### 0 `CLEONOS_SYSCALL_LOG_WRITE` @@ -659,6 +659,14 @@ u64 cleonos_syscall(u64 id, u64 arg0, u64 arg1, u64 arg2); - 返回:成功 `1`,失败 `0` - 说明:用纯色清屏。 +### 84 `CLEONOS_SYSCALL_KERNEL_VERSION` + +- 参数: +- `arg0`: `char *out_version` +- `arg1`: `u64 out_size` +- 返回:实际写入字节数(不含终止符),失败返回 `0` +- 说明:返回 CLKS 内核版本字符串(当前默认 `1.0.0-alpha`),内核会保证输出以 `\0` 结尾。 + ## 5. 用户态封装函数 用户态封装位于: @@ -687,6 +695,7 @@ u64 cleonos_syscall(u64 id, u64 arg0, u64 arg1, u64 arg2); - `cleonos_sys_dl_open()` / `cleonos_sys_dl_close()` / `cleonos_sys_dl_sym()` - `cleonos_sys_exec_pathv_io()` - `cleonos_sys_fb_info()` / `cleonos_sys_fb_blit()` / `cleonos_sys_fb_clear()` +- `cleonos_sys_kernel_version()` ## 6. 开发注意事项 @@ -697,7 +706,7 @@ u64 cleonos_syscall(u64 id, u64 arg0, u64 arg1, u64 arg2); ## 7. Wine 兼容说明 -- `wine/cleonos_wine_lib/runner.py` 当前已覆盖到 `0..83`(含 `DL_*`、`FB_*`)。 +- `wine/cleonos_wine_lib/runner.py` 当前已覆盖到 `0..84`(含 `DL_*`、`FB_*`、`KERNEL_VERSION`)。 - `DL_*`(`77..79`)在 Wine 中为“可运行兼容”实现: - `DL_OPEN`:加载 guest ELF 到当前 Unicorn 地址空间,返回稳定 `handle`,并做引用计数。 - `DL_SYM`:解析 ELF `SYMTAB/DYNSYM` 并返回 guest 可调用地址。 @@ -708,5 +717,7 @@ u64 cleonos_syscall(u64 id, u64 arg0, u64 arg1, u64 arg2); - `FB_BLIT` 实现内核同类参数校验并支持 `scale>=1` 绘制。 - 配合 Wine 参数 `--fb-window` 可将 framebuffer 实时显示到主机窗口(pygame 后端);未启用时保持内存缓冲模式。 - `FB_CLEAR` 支持清屏颜色写入。 +- `KERNEL_VERSION`(`84`)在 Wine 中返回内核版本字符串(当前默认 `1.0.0-alpha`)。 - Wine 在运行时崩溃场景下会生成与内核一致格式的“信号编码退出状态”,可通过 `WAITPID` 读取。 - Wine 当前音频 syscall 为占位实现:`AUDIO_AVAILABLE=0`,`AUDIO_PLAY_TONE=0`,`AUDIO_STOP=1`。 +- Wine 版本号策略固定为 `85.0.0-wine`(`85` = 当前实现 syscall 数量,后续保持不变)。 diff --git a/wine/README.md b/wine/README.md index 4f51dc8..2075c7d 100644 --- a/wine/README.md +++ b/wine/README.md @@ -38,7 +38,7 @@ python wine/cleonos_wine.py build/x86_64/ramdisk_root/shell/shell.elf --rootfs b ## 支持 - ELF64 (x86_64) PT_LOAD 段装载 -- CLeonOS `int 0x80` syscall 0..83(含 `FD_*`、`DL_*`、`FB_*`、`PROC_*`、`STATS_*`、`EXEC_PATHV_IO`) +- CLeonOS `int 0x80` syscall 0..84(含 `FD_*`、`DL_*`、`FB_*`、`PROC_*`、`STATS_*`、`EXEC_PATHV_IO`、`KERNEL_VERSION`) - TTY 输出与键盘输入队列 - rootfs 文件/目录访问(`FS_*`) - `/temp` 写入限制(`FS_MKDIR/WRITE/APPEND/REMOVE`) @@ -51,8 +51,14 @@ python wine/cleonos_wine.py build/x86_64/ramdisk_root/shell/shell.elf --rootfs b - 文件描述符(`FD_OPEN/FD_READ/FD_WRITE/FD_CLOSE/FD_DUP`) - 动态库兼容加载(`DL_OPEN/DL_CLOSE/DL_SYM`,基于 ELF 符号解析) - framebuffer 兼容(`FB_INFO/FB_BLIT/FB_CLEAR`,支持内存缓冲与窗口显示) +- 内核版本查询(`KERNEL_VERSION`) - 异常退出状态编码与故障元信息(`PROC_LAST_SIGNAL/PROC_FAULT_*`) +## 版本策略 + +- CLeonOS-Wine 版本号固定为:`85.0.0-wine` +- 该值来源于“当前实现 syscall 数量 = 85(0..84)”,按项目约定后续不再变更 + ## 参数 - `--no-kbd`:关闭输入线程 diff --git a/wine/cleonos_wine_lib/__pycache__/constants.cpython-313.pyc b/wine/cleonos_wine_lib/__pycache__/constants.cpython-313.pyc index 350f8067cb5410278eb80e511062ad408de05f38..a8f38d4fec5c39be2271e46e486ad86830ff035d 100644 GIT binary patch delta 1083 zcmZWmOHUhD7`2Vf!^SwV!MqY1Oaie9uY^|;AP_Sl4&yQLF%X`E17l-iY(fHyK7RBj{s4Zt*t496*GF=;sh_a~K00!65Hoh<7o}QH*d5cQ}r_oWLk2F~)ls z=Y34@0VX+xdz{97&fozbVv4hv<{W1D2oD*>Eax#t36J;~QI;1l&nJ)=!(%?h0vGXw zGGdJ5DHSX-0hvpP^BEK-ksz?d6rOPzNv;4~MT*a{%r&fV9jn~Hb8cddTUh5dHmG8g zJ0jJzNcDwCbyuXiCsNf!iW#&fnH5p(i>Pu!bRa}8g(xqUIK&nU*k*Cl#v|-O?XVo! z`3W@an2g9EZL(v*UYP78yBp5xjkby4scU3#cyM?ioj=-7zh4&be(IVWGh3hL3fg(p z_Jh^-KBZS{zIW`1+b{Ib?9uTJ!MG{lN3pQMRRPud()g%a(6S@k6XloUKduw-%JQ4b z_bS1({-=G~TBi>=f}^J1d6dp-Y9?PSk}rkuE5p%jIxbwE?_zJQXYq21 zyZ**87Rd++vj*f0hgCq=hYcFciMv`Z&qLAuM*qjrw{9$`gzelGXSF6*IH}fBJ1Mci zg6M>8EQ;d;xAWkVf7C5iovNBC35%wxtT7Z@2JGvf*UpxGQF#&Sij+hwp{PhDW6DC+ zAC;wqlK5Xguo_b&H5OlzrMRS|qM_dHd8M}O@OcfsC?yq1zFb9D8h@GCG4?cG!wlFAg}X-i(W^}z7WYbdZHB*#3nR?q xQ+>%DX?y4IsaSj$?Y$L?|Ds#)z`Hi*eUd(qNbv3T`a&yn4j^)IK-GeH0V delta 820 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 int: + if out_ptr == 0 or out_size <= 0: + return 0 + + max_copy = int(out_size) - 1 + if max_copy < 0: + return 0 + + payload = CLKS_VERSION_STRING.encode("utf-8", errors="replace") + if len(payload) > max_copy: + payload = payload[:max_copy] + + if not self._write_guest_bytes(uc, int(out_ptr), payload + b"\x00"): + return 0 + + return len(payload) + def _fb_info(self, uc: Uc, out_ptr: int) -> int: if out_ptr == 0: return 0