This commit is contained in:
2026-04-25 00:12:38 +08:00
parent 4c17f1a24b
commit bdbbbe64c7
11 changed files with 1251 additions and 975 deletions

View File

@@ -354,7 +354,7 @@ if(CLEONOS_ENABLE)
"-DLOG_LEVEL=STEP"
"-DLOG_TEXT=launching qemu run"
-P "${CL_LOG_EMIT_SCRIPT}"
COMMAND ${QEMU_X86_64} -M pc -m 1024M -boot order=d -cdrom "${ISO_IMAGE}" -drive "file=${DISK_IMAGE},format=raw,if=none,id=clksdisk,media=disk" -device "ide-hd,drive=clksdisk,bus=ide.0" -serial stdio
COMMAND ${QEMU_X86_64} -M pc -m 1024M -boot order=d -cdrom "${ISO_IMAGE}" -drive "file=${DISK_IMAGE},format=raw,if=none,id=clksdisk,media=disk" -device "ide-hd,drive=clksdisk,bus=ide.0" -netdev "user,id=clksnet0" -device "e1000,netdev=clksnet0" -serial stdio
DEPENDS iso disk-image
USES_TERMINAL
)
@@ -365,7 +365,7 @@ if(CLEONOS_ENABLE)
"-DLOG_LEVEL=STEP"
"-DLOG_TEXT=launching qemu debug (-s -S)"
-P "${CL_LOG_EMIT_SCRIPT}"
COMMAND ${QEMU_X86_64} -M pc -m 1024M -boot order=d -cdrom "${ISO_IMAGE}" -drive "file=${DISK_IMAGE},format=raw,if=none,id=clksdisk,media=disk" -device "ide-hd,drive=clksdisk,bus=ide.0" -serial stdio -s -S
COMMAND ${QEMU_X86_64} -M pc -m 1024M -boot order=d -cdrom "${ISO_IMAGE}" -drive "file=${DISK_IMAGE},format=raw,if=none,id=clksdisk,media=disk" -device "ide-hd,drive=clksdisk,bus=ide.0" -netdev "user,id=clksnet0" -device "e1000,netdev=clksnet0" -serial stdio -s -S
DEPENDS iso disk-image
USES_TERMINAL
)

View File

@@ -128,6 +128,7 @@ list(SORT DOOMGENERIC_DEP_SOURCES_ABS)
set(USER_SHELL_COMMAND_APPS
help args ls cat grep head tail wc cut uniq sort pwd cd exec pid spawn wait sleep yield
ping
bg fg jobs kill ps top
procstat sysstat
diskinfo mkfsfat32 mount partctl

View File

@@ -33,6 +33,7 @@ static int ush_cmd_help(void) {
ush_writeln(" mkfsfat32 [label]");
ush_writeln(" mount [path] (default suggested: /temp/disk)");
ush_writeln(" partctl <subcommand> (mbr partition control: list/init-mbr/create/delete/set-boot)");
ush_writeln(" ping <a.b.c.d> [count]");
ush_writeln(" pid");
ush_writeln(" spawn <path|name> [args...] / bg <path|name> [args...]");
ush_writeln(" wait <pid> / fg [pid]");

181
cleonos/c/apps/ping_main.c Normal file
View File

@@ -0,0 +1,181 @@
#include "cmd_runtime.h"
#include <stdio.h>
static int ush_ping_parse_ipv4_be(const char *text, u64 *out_ipv4_be) {
u64 acc = 0ULL;
u64 value = 0ULL;
u64 parts = 0ULL;
u64 has_digit = 0ULL;
u64 i = 0ULL;
if (text == (const char *)0 || out_ipv4_be == (u64 *)0) {
return 0;
}
while (text[i] != '\0') {
char ch = text[i];
if (ch >= '0' && ch <= '9') {
value = (value * 10ULL) + (u64)(ch - '0');
if (value > 255ULL) {
return 0;
}
has_digit = 1ULL;
} else if (ch == '.') {
if (has_digit == 0ULL || parts >= 3ULL) {
return 0;
}
acc = (acc << 8ULL) | value;
parts++;
value = 0ULL;
has_digit = 0ULL;
} else {
return 0;
}
i++;
}
if (has_digit == 0ULL || parts != 3ULL) {
return 0;
}
acc = (acc << 8ULL) | value;
*out_ipv4_be = acc & 0xFFFFFFFFULL;
return 1;
}
static void ush_ping_print_ipv4(u64 ipv4_be) {
unsigned int a = (unsigned int)((ipv4_be >> 24ULL) & 0xFFULL);
unsigned int b = (unsigned int)((ipv4_be >> 16ULL) & 0xFFULL);
unsigned int c = (unsigned int)((ipv4_be >> 8ULL) & 0xFFULL);
unsigned int d = (unsigned int)(ipv4_be & 0xFFULL);
(void)printf("%u.%u.%u.%u", a, b, c, d);
}
static int ush_cmd_ping(const char *arg) {
char host[USH_PATH_MAX];
char count_text[32];
const char *rest = "";
const char *rest2 = "";
u64 target_ipv4_be = 0ULL;
u64 local_ipv4_be;
u64 count = 4ULL;
u64 i;
u64 received = 0ULL;
if (arg == (const char *)0 || arg[0] == '\0') {
(void)puts("ping: usage ping <a.b.c.d> [count]");
return 0;
}
if (ush_split_first_and_rest(arg, host, (u64)sizeof(host), &rest) == 0) {
(void)puts("ping: usage ping <a.b.c.d> [count]");
return 0;
}
if (ush_ping_parse_ipv4_be(host, &target_ipv4_be) == 0) {
(void)puts("ping: invalid ipv4 address");
return 0;
}
if (rest != (const char *)0 && rest[0] != '\0') {
if (ush_split_first_and_rest(rest, count_text, (u64)sizeof(count_text), &rest2) == 0) {
(void)puts("ping: usage ping <a.b.c.d> [count]");
return 0;
}
if (rest2 != (const char *)0 && rest2[0] != '\0') {
(void)puts("ping: usage ping <a.b.c.d> [count]");
return 0;
}
if (ush_parse_u64_dec(count_text, &count) == 0 || count == 0ULL || count > 64ULL) {
(void)puts("ping: count must be in range 1..64");
return 0;
}
}
if (cleonos_sys_net_available() == 0ULL) {
(void)puts("ping: network unavailable (e1000 not ready)");
return 0;
}
local_ipv4_be = cleonos_sys_net_ipv4_addr();
(void)fputs("PING ", 1);
ush_ping_print_ipv4(target_ipv4_be);
(void)fputs(" from ", 1);
ush_ping_print_ipv4(local_ipv4_be);
(void)putchar('\n');
for (i = 0ULL; i < count; i++) {
u64 ok = cleonos_sys_net_ping(target_ipv4_be, 300000ULL);
if (ok != 0ULL) {
(void)fputs("reply from ", 1);
ush_ping_print_ipv4(target_ipv4_be);
(void)printf(" seq=%llu\n", (unsigned long long)(i + 1ULL));
received++;
} else {
(void)fputs("timeout from ", 1);
ush_ping_print_ipv4(target_ipv4_be);
(void)printf(" seq=%llu\n", (unsigned long long)(i + 1ULL));
}
if (i + 1ULL < count) {
(void)cleonos_sys_sleep_ticks(30ULL);
}
}
(void)puts("");
(void)printf("ping stats: tx=%llu rx=%llu loss=%llu\n", (unsigned long long)count, (unsigned long long)received,
(unsigned long long)(count - received));
return (received > 0ULL) ? 1 : 0;
}
int cleonos_app_main(void) {
ush_cmd_ctx ctx;
ush_cmd_ret ret;
ush_state sh;
char initial_cwd[USH_PATH_MAX];
int has_context = 0;
int success = 0;
const char *arg = "";
ush_zero(&ctx, (u64)sizeof(ctx));
ush_zero(&ret, (u64)sizeof(ret));
ush_init_state(&sh);
ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd);
if (ush_command_ctx_read(&ctx) != 0) {
if (ctx.cmd[0] != '\0' && ush_streq(ctx.cmd, "ping") != 0) {
has_context = 1;
arg = ctx.arg;
if (ctx.cwd[0] == '/') {
ush_copy(sh.cwd, (u64)sizeof(sh.cwd), ctx.cwd);
ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd);
}
}
}
success = ush_cmd_ping(arg);
if (has_context != 0) {
if (ush_streq(sh.cwd, initial_cwd) == 0) {
ret.flags |= USH_CMD_RET_FLAG_CWD;
ush_copy(ret.cwd, (u64)sizeof(ret.cwd), sh.cwd);
}
if (sh.exit_requested != 0) {
ret.flags |= USH_CMD_RET_FLAG_EXIT;
ret.exit_code = sh.exit_code;
}
(void)ush_command_ret_write(&ret);
}
return (success != 0) ? 0 : 1;
}

View File

@@ -60,6 +60,22 @@ typedef struct cleonos_fb_blit_req {
u64 scale;
} cleonos_fb_blit_req;
typedef struct cleonos_net_udp_send_req {
u64 dst_ipv4_be;
u64 dst_port;
u64 src_port;
u64 payload_ptr;
u64 payload_len;
} cleonos_net_udp_send_req;
typedef struct cleonos_net_udp_recv_req {
u64 out_payload_ptr;
u64 payload_capacity;
u64 out_src_ipv4_ptr;
u64 out_src_port_ptr;
u64 out_dst_port_ptr;
} cleonos_net_udp_recv_req;
#define CLEONOS_SYSCALL_LOG_WRITE 0ULL
#define CLEONOS_SYSCALL_TIMER_TICKS 1ULL
#define CLEONOS_SYSCALL_TASK_COUNT 2ULL
@@ -155,6 +171,11 @@ typedef struct cleonos_fb_blit_req {
#define CLEONOS_SYSCALL_DISK_MOUNT_PATH 92ULL
#define CLEONOS_SYSCALL_DISK_READ_SECTOR 93ULL
#define CLEONOS_SYSCALL_DISK_WRITE_SECTOR 94ULL
#define CLEONOS_SYSCALL_NET_AVAILABLE 95ULL
#define CLEONOS_SYSCALL_NET_IPV4_ADDR 96ULL
#define CLEONOS_SYSCALL_NET_PING 97ULL
#define CLEONOS_SYSCALL_NET_UDP_SEND 98ULL
#define CLEONOS_SYSCALL_NET_UDP_RECV 99ULL
u64 cleonos_syscall(u64 id, u64 arg0, u64 arg1, u64 arg2);
u64 cleonos_sys_log_write(const char *message, u64 length);
@@ -252,5 +273,10 @@ u64 cleonos_sys_disk_mounted(void);
u64 cleonos_sys_disk_mount_path(char *out_path, u64 out_size);
u64 cleonos_sys_disk_read_sector(u64 lba, void *out_sector);
u64 cleonos_sys_disk_write_sector(u64 lba, const void *sector_data);
u64 cleonos_sys_net_available(void);
u64 cleonos_sys_net_ipv4_addr(void);
u64 cleonos_sys_net_ping(u64 dst_ipv4_be, u64 poll_budget);
u64 cleonos_sys_net_udp_send(const cleonos_net_udp_send_req *req);
u64 cleonos_sys_net_udp_recv(cleonos_net_udp_recv_req *req);
#endif

View File

@@ -47,6 +47,18 @@ long long llabs(long long value) {
return (value < 0LL) ? -value : value;
}
double fabs(double value) {
return (value < 0.0) ? -value : value;
}
float fabsf(float value) {
return (value < 0.0f) ? -value : value;
}
long double fabsl(long double value) {
return (value < 0.0L) ? -value : value;
}
int atoi(const char *text) {
return (int)strtol(text, (char **)0, 10);
}

View File

@@ -411,3 +411,23 @@ u64 cleonos_sys_disk_read_sector(u64 lba, void *out_sector) {
u64 cleonos_sys_disk_write_sector(u64 lba, const void *sector_data) {
return cleonos_syscall(CLEONOS_SYSCALL_DISK_WRITE_SECTOR, lba, (u64)sector_data, 0ULL);
}
u64 cleonos_sys_net_available(void) {
return cleonos_syscall(CLEONOS_SYSCALL_NET_AVAILABLE, 0ULL, 0ULL, 0ULL);
}
u64 cleonos_sys_net_ipv4_addr(void) {
return cleonos_syscall(CLEONOS_SYSCALL_NET_IPV4_ADDR, 0ULL, 0ULL, 0ULL);
}
u64 cleonos_sys_net_ping(u64 dst_ipv4_be, u64 poll_budget) {
return cleonos_syscall(CLEONOS_SYSCALL_NET_PING, dst_ipv4_be, poll_budget, 0ULL);
}
u64 cleonos_sys_net_udp_send(const cleonos_net_udp_send_req *req) {
return cleonos_syscall(CLEONOS_SYSCALL_NET_UDP_SEND, (u64)req, 0ULL, 0ULL);
}
u64 cleonos_sys_net_udp_recv(cleonos_net_udp_recv_req *req) {
return cleonos_syscall(CLEONOS_SYSCALL_NET_UDP_RECV, (u64)req, 0ULL, 0ULL);
}

2
clks

Submodule clks updated: 82ef5fd38e...f7c89a3420

View File

@@ -83,7 +83,7 @@ u64 cleonos_syscall(u64 id, u64 arg0, u64 arg1, u64 arg2);
- `/proc/<pid>`:指定 PID 快照文本
- `/proc` 为只读;写入类 syscall 不支持。
## 4. Syscall 列表0~94
## 4. Syscall 列表0~99
### 0 `CLEONOS_SYSCALL_LOG_WRITE`
@@ -731,6 +731,38 @@ u64 cleonos_syscall(u64 id, u64 arg0, u64 arg1, u64 arg2);
- 返回:成功 `1`,失败 `0`
- 说明:按 LBA 写入单个扇区512B。该 syscall 在 USC 策略中默认视为高风险操作。
### 95 `CLEONOS_SYSCALL_NET_AVAILABLE`
- 参数:无
- 返回:`1` 表示网络栈可用e1000 初始化成功),`0` 表示不可用。
### 96 `CLEONOS_SYSCALL_NET_IPV4_ADDR`
- 参数:无
- 返回:当前 IPv4 地址(`u32`,以网络字节序放在返回值低 32 位)。
- 说明:当前默认静态地址为 `10.0.2.15`QEMU usernet 常见配置)。
### 97 `CLEONOS_SYSCALL_NET_PING`
- 参数:
- `arg0`: `u64 dst_ipv4_be`(目标 IPv4网络字节序
- `arg1`: `u64 poll_budget`(轮询预算;`0` 使用内核默认)
- 返回:成功收到 echo reply 返回 `1`,否则返回 `0`
### 98 `CLEONOS_SYSCALL_NET_UDP_SEND`
- 参数:
- `arg0`: `const struct { u64 dst_ipv4_be; u64 dst_port; u64 src_port; u64 payload_ptr; u64 payload_len; } *req`
- 返回:实际发送 payload 字节数;失败返回 `0`
- 说明:当前实现为最小 UDP 能力,`payload_len` 建议不超过 MTU 可承载范围。
### 99 `CLEONOS_SYSCALL_NET_UDP_RECV`
- 参数:
- `arg0`: `struct { u64 out_payload_ptr; u64 payload_capacity; u64 out_src_ipv4_ptr; u64 out_src_port_ptr; u64 out_dst_port_ptr; } *req`
- 返回:实际拷贝到 `out_payload_ptr` 的字节数;无数据/失败返回 `0`
- 说明:`out_src_*`/`out_dst_*` 指针可为 `0`(表示不关心该字段)。
## 5. 用户态封装函数
用户态封装位于:
@@ -763,6 +795,8 @@ u64 cleonos_syscall(u64 id, u64 arg0, u64 arg1, u64 arg2);
- `cleonos_sys_disk_present()` / `cleonos_sys_disk_size_bytes()` / `cleonos_sys_disk_sector_count()`
- `cleonos_sys_disk_formatted()` / `cleonos_sys_disk_format_fat32()` / `cleonos_sys_disk_mount()` / `cleonos_sys_disk_mounted()` / `cleonos_sys_disk_mount_path()`
- `cleonos_sys_disk_read_sector()` / `cleonos_sys_disk_write_sector()`
- `cleonos_sys_net_available()` / `cleonos_sys_net_ipv4_addr()` / `cleonos_sys_net_ping()`
- `cleonos_sys_net_udp_send()` / `cleonos_sys_net_udp_recv()`
## 6. 开发注意事项
@@ -773,7 +807,7 @@ u64 cleonos_syscall(u64 id, u64 arg0, u64 arg1, u64 arg2);
## 7. Wine 兼容说明
- `wine/cleonos_wine_lib/runner.py` 当前已覆盖到 `0..94`(含 `DL_*``FB_*``KERNEL_VERSION``DISK_*`)。
- `wine/cleonos_wine_lib/runner.py` 当前已覆盖到 `0..99`(含 `DL_*``FB_*``KERNEL_VERSION``DISK_*``NET_*`)。
- `DL_*``77..79`)在 Wine 中为“可运行兼容”实现:
- `DL_OPEN`:加载 guest ELF 到当前 Unicorn 地址空间,返回稳定 `handle`,并做引用计数。
- `DL_SYM`:解析 ELF `SYMTAB/DYNSYM` 并返回 guest 可调用地址。
@@ -790,6 +824,7 @@ u64 cleonos_syscall(u64 id, u64 arg0, u64 arg1, u64 arg2);
- `DISK_FORMAT_FAT32` 会初始化/重置 Wine rootfs 下的虚拟磁盘目录。
- `DISK_MOUNT`/`DISK_MOUNT_PATH` 支持挂载点管理,并与 `FS_MKDIR/WRITE/APPEND/REMOVE` 的路径规则联动。
- `DISK_READ_SECTOR`/`DISK_WRITE_SECTOR``93..94`)在 Wine 中已实现为 512B 原始扇区读写host 文件后端)。
- 网络 syscall`95..99`)在 Wine 当前为兼容占位实现(统一返回 `0`);即 Wine 运行模式下不会提供真实网络收发。
- Wine 在运行时崩溃场景下会生成与内核一致格式的“信号编码退出状态”,可通过 `WAITPID` 读取。
- Wine 当前音频 syscall 为占位实现:`AUDIO_AVAILABLE=0``AUDIO_PLAY_TONE=0``AUDIO_STOP=1`
- Wine 版本号策略固定为 `85.0.0-wine`(历史兼容号;不会随 syscall 扩展继续增长)。

2
kit

Submodule kit updated: a8dfe5c4eb...20dd7394ef

2
wine

Submodule wine updated: e83774f1b3...80586d676d