feat: Linux ABI P0-P6, BMIDE DMA, ImageSee, 4KiB page pool and Explorer hardening
This commit is contained in:
1 parent
ebd43ef9da
commit
6f856992da
41 files changed
+8696
-2470
No files matched your search
@@ -0,0 +1,114 @@
|
||||
# ImageSee 图像解码库
|
||||
|
||||
`vpsdk/imagesee` 是一个纯用户态的 PNG / JPEG 解码库,配套示例应用
|
||||
`Apps/ImageSee` 在窗口中并排显示解码结果。
|
||||
|
||||
## 1. 目录与模块
|
||||
|
||||
```text
|
||||
vpsdk/imagesee/
|
||||
├── imagesee.vp 公共 API:load / decode_memory / checksum
|
||||
├── image.vp Image 类型与像素打包(0xAARRGGBB)
|
||||
├── inflate.vp zlib / DEFLATE(stored / fixed / dynamic Huffman)
|
||||
├── png.vp PNG:全部颜色类型、1/2/4/8/16 位、Adam7
|
||||
└── jpeg.vp JPEG:baseline/extended sequential、4:4:4/4:2:2/4:2:0
|
||||
|
||||
Apps/ImageSee/ 示例应用(窗口 + 两块 FBCanvas)
|
||||
Assets/images/ 示例图片(由 Scripts/gen_imagesee_assets.py 生成)
|
||||
```
|
||||
|
||||
## 2. 公共 API
|
||||
|
||||
```python
|
||||
import vpsdk.imagesee.imagesee as imagesee
|
||||
|
||||
img = imagesee.load("/IMAGES/SAMPLE.PNG") # 失败返回 None
|
||||
if img is not None:
|
||||
w = img.width
|
||||
h = img.height
|
||||
c = img.pixels[y * w + x] # 0xAARRGGBB
|
||||
r = (c >> 16) & 0xFF
|
||||
g = (c >> 8) & 0xFF
|
||||
b = c & 0xFF
|
||||
|
||||
img2 = imagesee.decode_memory(buf, size) # 已有字节流时使用
|
||||
sum32 = imagesee.checksum(img) # FNV-1a,用于回归比对
|
||||
name = imagesee.format_name(img) # "png" / "jpeg"
|
||||
```
|
||||
|
||||
像素格式与 ViperOS 窗口 / `FBCanvas` 一致:`0xAARRGGBB`,alpha 字节目前由
|
||||
合成层忽略,解码器一律输出 255(PNG 的透明像素保留 alpha=0 于像素字中)。
|
||||
|
||||
## 3. PNG 支持
|
||||
|
||||
- 签名、IHDR、PLTE、tRNS、IDAT(可多块)、IEND
|
||||
- 颜色类型:0(灰度)、2(RGB)、3(调色板)、4(灰度+alpha)、6(RGBA)
|
||||
- 位深:1/2/4/8/16(按 PNG 规则缩小到 8 位输出)
|
||||
- 过滤:None / Sub / Up / Average / Paeth
|
||||
- Adam7 隔行扫描
|
||||
- 解码后输出 RGBA;调色板 tRNS、灰度和 RGB 的透明色都会转成 alpha=0
|
||||
|
||||
## 4. JPEG 支持
|
||||
|
||||
- Baseline / extended sequential Huffman(SOF0 / SOF1)
|
||||
- 灰度与 YCbCr,色度子采样 4:4:4 / 4:2:2 / 4:2:0(以及任意 H/V 因子)
|
||||
- DQT(8/16 位)、DHT、DRI + RSTn 重启标记
|
||||
- 组件按 ID 识别(1=Y、2=Cb、3=Cr),也兼容 Adobe APP14 的 RGB 变换
|
||||
- 8×8 浮点 IDCT,YCbCr → RGB 后输出
|
||||
|
||||
**限制**:渐进式 JPEG(SOF2)目前明确返回 `None`(不做“解一半”的错误输出);
|
||||
CMYK/YCCK 返回 `None`;不支持 EXIF 方向、缩略图、算术编码。
|
||||
|
||||
## 5. 示例应用
|
||||
|
||||
`/APPS/IMAGESEE.ELF` 启动后:
|
||||
|
||||
1. 依次解码并打印 `/IMAGES/SAMPLE.PNG`、`PHOTO.JPG`、`GRAY.JPG`、
|
||||
`PAL.PNG`、`INTER.PNG` 的尺寸、FNV 校验和与 3 个采样像素;
|
||||
2. 创建窗口,左画 PNG、右画 JPEG(等比缩放居中);
|
||||
3. 失败时对应面板显示品红/深蓝棋盘,串口打印 `FAILED stage=N`。
|
||||
|
||||
`build.py` 会:
|
||||
|
||||
- 编译 `Apps/ImageSee` 到 `disk/apps/imagesee.elf`
|
||||
- 把 `Assets/images/*.png|jpg` 复制到 `disk/images/`
|
||||
- 内核 `main.vp` 在 Explorer/FontDemo 之后自动 spawn ImageSee(pid=7)
|
||||
|
||||
重建示例图片:
|
||||
|
||||
```powershell
|
||||
python Scripts/gen_imagesee_assets.py # 需要 Pillow,仅生成资源时使用
|
||||
```
|
||||
|
||||
## 6. 已验证
|
||||
|
||||
2026-10-28,QEMU 512MB,无头启动:
|
||||
|
||||
| 文件 | 类型 | 结果 |
|
||||
|---|---|---|
|
||||
| sample.png | RGBA,非隔行 | 解码像素/校验和与 PIL 完全一致 |
|
||||
| pal.png | 调色板 + tRNS | 完全一致 |
|
||||
| inter.png | RGBA,Adam7,alpha 渐变 | 完全一致 |
|
||||
| photo.jpg | baseline 4:2:0 | 尺寸/采样点与 PIL 在 ±11 内(IDCT/上采样差异) |
|
||||
| gray.jpg | 灰度 baseline | 采样点完全一致 |
|
||||
|
||||
## 7. Explorer 桌面壁纸
|
||||
|
||||
Explorer 启动时调用 `imagesee.load("/sys/images/screen/background.jpg")`:
|
||||
|
||||
- 成功:按“cover”等比裁切铺满 framebuffer,任务栏/窗口叠加在壁纸上
|
||||
- 失败(文件不存在/解码失败):重试一次;仍失败则保持原来的深色纯色背景
|
||||
- 构建:`build.py` 把 `Assets/background.jpg` 复制到
|
||||
`disk/sys/images/screen/background.jpg`
|
||||
- 重新生成壁纸:`python Scripts/gen_imagesee_assets.py`(960×540 baseline JPEG)
|
||||
|
||||
## 8. 内存
|
||||
|
||||
解码使用 `stdlib.malloc`(mmap 后端,`free` 为空操作)。一次 `load` 会保留:
|
||||
|
||||
- 压缩文件字节
|
||||
- DEFLATE 解压后的扫描线缓冲(PNG)
|
||||
- 最终 `w*h*4` 像素
|
||||
- JPEG 的量化系数与分量平面
|
||||
|
||||
因此适合中小图片(示例 320×220)。超大图片(>4096²)不建议在当前堆上尝试。
|
||||
+382
@@ -0,0 +1,382 @@
|
||||
# ViperOS syscall 与 Linux x86-64 ABI 对齐计划
|
||||
|
||||
状态:**P0–P6 完成**(含明确受限项;内核/应用构建通过,`fork`、`wait4`、信号投递已在 QEMU 冒烟验证)
|
||||
最后更新:2026-10-28
|
||||
|
||||
目标:让 ViperOS 的 syscall 面逐步收敛到 Linux x86-64 ABI,最终能够**直接运行静态/动态链接的 glibc 程序**。
|
||||
|
||||
非目标(至少本计划内不做):
|
||||
|
||||
- 网络协议栈相关 syscall(socket/connect/…)
|
||||
- ptrace / seccomp / cgroup / namespace
|
||||
- 完整 VFS(符号链接、硬链接、inode 语义)
|
||||
- 与 Linux 内核模块、io_uring、epoll 的兼容
|
||||
|
||||
---
|
||||
|
||||
## 1. 现状
|
||||
|
||||
### 1.1 入口与调用约定
|
||||
|
||||
| 项目 | 现状 |
|
||||
|---|---|
|
||||
| 指令 | `syscall`(MSR `STAR`/`LSTAR`/`FMASK`),另注册了 DPL=3 的 `int 0x80` 遗留门 |
|
||||
| 调用号 | `rax` |
|
||||
| 参数 | `rdi`, `rsi`, `rdx`, `r10`, `r8`, `r9`(与 Linux 一致) |
|
||||
| 返回 | `rax`;目前正负混用 |
|
||||
| 错误 | 无 `errno`、无 TLS;部分返回 `-1`,部分返回 FAT32 `FRESULT` **正数**,未知调用号返回 `0` |
|
||||
| 表 | `VKernel/Kernel/intr/syscall.vp` 与 `vpsdk/syscall.vp` 两份手工镜像 |
|
||||
|
||||
### 1.2 已实现的调用
|
||||
|
||||
权威列表见 `Scripts/syscall_table.py`(`build.py` 构建前自动同步内核与 SDK)。
|
||||
截至 P6,Linux 号段已覆盖:
|
||||
|
||||
```text
|
||||
文件 open/openat/close/read/write/pread/pwrite/lseek/stat/fstat/newfstatat/
|
||||
getdents64/dup/dup2/dup3/fcntl/mkdir/unlink/rename/rmdir/getcwd/chdir/
|
||||
access/faccessat/readlink/readlinkat
|
||||
内存 brk/mmap/munmap/mprotect/mremap/madvise
|
||||
进程 getpid/getppid/gettid/exit/exit_group/wait4/clone/fork/execve
|
||||
线程 arch_prctl(FS)/set_tid_address/set_robust_list/futex/sched_yield
|
||||
时间 clock_gettime/clock_getres/gettimeofday/nanosleep
|
||||
信号 rt_sigaction/rt_sigprocmask/rt_sigreturn/kill
|
||||
IPC pipe/pipe2/readv/writev/poll(超时桩)
|
||||
系统 uname/getuid/geteuid/getgid/getegid/prlimit64/getrandom/reboot
|
||||
```
|
||||
|
||||
私有段仅剩兼容别名(`LOAD_SO`/`SO_CALL1`/`SPAWN_PROC`/`THREAD_CREATE_OLD`/
|
||||
`REBOOT`/`SHUTDOWN`)。
|
||||
|
||||
### 1.3 已知偏差
|
||||
|
||||
- `execve(59)` 通过“加载新进程 + 退出调用者”模拟,PID 会改变
|
||||
- `fork(57)` / `clone(56)` 会复制/共享地址空间;`CLONE_VM` 无 `CLONE_THREAD`
|
||||
的 vfork 场景按同进程线程近似
|
||||
- 信号只在 **syscall 返回** 时投递(没有中断返回钩子);`ucontext_t` 为自定义
|
||||
紧凑布局,`siglongjmp` 不可用
|
||||
- `futex` 为“查值 + yield”轮询;`poll` 恒返回 0(仅超时语义)
|
||||
- `exit_group(231)` 终止进程内所有线程;进程退出不回收管道/文件引用计数
|
||||
- fork/exec 继承的非管道 fd 标记为两侧共享:close 只清槽位不释放对象(避免
|
||||
交叉释放;代价是泄漏)
|
||||
- 资源上限:8 进程 / 每进程 8 线程 / 16 fd / 8 目录句柄 / 64 VMA / 8 管道
|
||||
- P1 已补:`openat` / `fstat` / `newfstatat` / `getdents64` / `dup` / `fcntl`,
|
||||
私有目录调用已删除
|
||||
- P2 已补:`brk` / `mprotect` / `munmap` / `mremap` / `madvise`,文件映射
|
||||
- P3–P6 已补:启动栈/auxv、`PT_INTERP`/ET_DYN、`execve`、`wait4`、Linux
|
||||
`clone`/`fork`、TLS、时间、管道、信号投递、`reboot(169)`
|
||||
|
||||
### 1.4 维护风险
|
||||
|
||||
两份 `enum Syscall` 靠人工同步。P0 起改为**生成**:
|
||||
|
||||
```text
|
||||
Scripts/syscall_table.py ← 唯一权威表
|
||||
│
|
||||
├─ VKernel/Kernel/intr/syscall.vp [BEGIN/END GENERATED]
|
||||
└─ vpsdk/syscall.vp [BEGIN/END GENERATED]
|
||||
```
|
||||
|
||||
`build.py` 在编译前运行生成器;两边不一致会直接覆盖,不再依赖记忆。
|
||||
|
||||
---
|
||||
|
||||
## 2. 目标 ABI 契约
|
||||
|
||||
### 2.1 调用与返回
|
||||
|
||||
- `rax` = 调用号,参数 `rdi/rsi/rdx/r10/r8/r9`
|
||||
- 成功:返回非负值(字节数、fd、地址、0…)
|
||||
- 失败:返回 `-errno`(`-ENOENT`、`-EINVAL`…),**不再返回 `FRESULT` 正数**
|
||||
- 未实现:`-ENOSYS`
|
||||
- 指针参数越界/为空:`-EFAULT`
|
||||
- 用户态 `errno` 由 glibc 从返回值设置,内核不维护 `errno`
|
||||
|
||||
### 2.2 数据结构
|
||||
|
||||
内核新增 `abi/linux.vp`(内核工程 include 增加仓库根目录),字段布局按 x86-64 Linux;
|
||||
SDK 侧需要结构体时可直接 `import abi.linux`。两者共用同一份定义,避免布局漂移。
|
||||
|
||||
| 类型 | 大小 | 用途 |
|
||||
|---|---:|---|
|
||||
| `abi.linux_stat` | 144 | `stat/fstat/newfstatat` |
|
||||
| `abi.linux_dirent64` | 19+name | `getdents64` |
|
||||
| `abi.linux_timespec` | 16 | 时间 |
|
||||
| `abi.linux_utsname` | 390 | `uname` |
|
||||
| `abi.linux_rlimit` | 16 | `prlimit64` |
|
||||
| `abi.iovec` | 16 | `readv/writev` |
|
||||
|
||||
### 2.3 启动栈(P3)
|
||||
|
||||
glibc 不读 `_start(argc, argv)`,它要求内核按 Linux 方式布置用户栈:
|
||||
|
||||
```text
|
||||
[argc][argv0..argvN][NULL][envp...][NULL][auxv pairs][AT_NULL]
|
||||
```
|
||||
|
||||
必须提供的 auxv:`AT_PHDR`、`AT_PHENT`、`AT_PHNUM`、`AT_ENTRY`、`AT_BASE`、
|
||||
`AT_PAGESZ`、`AT_RANDOM`、`AT_UID/EUID/GID/EGID`、`AT_SECURE=0`、
|
||||
`AT_EXECFN`、`AT_SYSINFO_EHDR`(可选,无 vDSO 时省略)。
|
||||
|
||||
动态链接:`PT_INTERP` 指向的解释器按 ET_DYN 基址(`0x70000000`)加载,
|
||||
主程序 PIE 基址 `0x60000000`,`AT_BASE` 指向解释器,`AT_PHDR/AT_ENTRY`
|
||||
仍指向主程序。系统镜像中需要实际存在该解释器与 libc。
|
||||
|
||||
### 2.4 TLS 与线程(P4)
|
||||
|
||||
- `arch_prctl(ARCH_SET_FS)`:设置每线程 `IA32_FS_BASE`
|
||||
- 线程切换时保存/恢复 `FS_BASE`
|
||||
- `set_tid_address`、`set_robust_list`、`rseq`(可为 `-ENOSYS`)
|
||||
- futex 至少覆盖 `FUTEX_WAIT/FUTEX_WAKE`(glibc pthread 必需)
|
||||
|
||||
### 2.5 兼容口径
|
||||
|
||||
- `uname().sysname` 报 `"Linux"`,`release` 报一个 Linux 风格版本号;真实产品名放在 `version` 字段。这样大量脚本/构建系统不会因 `sysname != Linux` 走特殊分支。
|
||||
- 文件权限位使用固定值:普通文件 `0644`、目录 `0755`;FAT32 没有 uid/gid。
|
||||
|
||||
---
|
||||
|
||||
## 3. 阶段计划
|
||||
|
||||
### P0 — ABI 契约与基础设施(本次完成,待编译验证)
|
||||
|
||||
- [x] `abi/linux.vp`:errno、`O_*`、`AT_*`、`DT_*`、`PROT_*`、`MAP_*`、`ARCH_*`、结构体
|
||||
- [x] 统一错误模型:Linux 号段调用返回 `-errno`;未知调用 `-ENOSYS`
|
||||
(私有 0x1000+ 段在 P6 删除前保留旧返回值)
|
||||
- [x] `open` 采用 Linux `O_*`,内核翻译到 FAT32 `FA_*`
|
||||
- [x] `lseek` 返回新偏移(而不是状态码),支持 64 位 offset(FAT32 上限内)
|
||||
- [x] 新调用:`uname` `getuid/geteuid/getgid/getegid` `getppid` `gettid`
|
||||
`getcwd` `chdir` `access` `faccessat` `readlink` `readlinkat`
|
||||
`set_tid_address` `set_robust_list` `rseq` `prlimit64` `getrandom`
|
||||
- [x] `Process.cwd`(默认 `/`)
|
||||
- [x] syscall 表由 `Scripts/syscall_table.py` 生成,`build.py` 自动同步
|
||||
- [x] `vpsdk` 增加对应包装与常量
|
||||
|
||||
验收:现有应用行为不回退;所有失败路径可观察到负 errno;`Scripts/syscall_table.py --check` 通过。
|
||||
|
||||
### P1 — 文件系统 ABI(本次完成,待编译验证)
|
||||
|
||||
- [x] `openat(257)`(`AT_FDCWD` + 绝对路径 + cwd 相对路径)
|
||||
- [x] `fstat(5)`、`newfstatat(262)`、`statx(332)`(返回 `-ENOSYS`,glibc 回退)
|
||||
- [x] `getdents64(217)` + 目录 fd(`O_DIRECTORY`)
|
||||
- [x] `dup(32)` / `dup2(33)` / `dup3(292)`、`fcntl(72)`(`F_GETFL/F_SETFL/F_DUPFD`)
|
||||
- [x] `pread64(17)` / `pwrite64(18)`
|
||||
- [x] `rename(82)`、`rmdir(84)`、`unlinkat(263)`
|
||||
- [x] 删除私有 `OPENDIR/READDIR/CLOSEDIR`
|
||||
- [x] SDK 的 `opendir/readdir/closedir` 改由 `openat + getdents64 + close` 实现,
|
||||
Terminal 等调用方无需改动
|
||||
|
||||
验收:`ls` 走 `openat + getdents64`;SDK 的 `open` 也统一经 `openat(AT_FDCWD)`;
|
||||
`ld.so` 的 `openat/read/fstat/getdents64` 路径可用(文件映射属于 P2)。
|
||||
|
||||
P1 已知限制:
|
||||
|
||||
- `getdents64` 每次只返回一条记录(glibc 合法,只是多一次 syscall)
|
||||
- `d_ino` 固定 1、`d_off` 固定 0;`telldir/seekdir/rewinddir` 暂不保证
|
||||
- `dirfd != AT_FDCWD` 的相对路径查找返回 `-ENOTSUP`(P3/P6 再补目录 fd 反查)
|
||||
- `statx` 返回 `-ENOSYS`,glibc 回退到 `newfstatat`
|
||||
- `rename` 只支持同一 FAT32 卷内;`dup` 共享文件偏移,最后一次 `close` 才释放对象
|
||||
|
||||
### P2 — 内存管理(本次完成,待编译验证)
|
||||
|
||||
- [x] `brk(12)`:独立 brk 区(`0x40000000` 起),按页增长/收缩
|
||||
- [x] `mmap` 真语义:`MAP_FIXED`、`PROT_*`、失败返回 `MAP_FAILED`(-1)
|
||||
- [x] FAT32 文件映射:把文件内容复制进新页(`MAP_PRIVATE` 语义)
|
||||
- [x] `munmap(11)` 真正解映射并把物理页归还 buddy
|
||||
- [x] `mprotect(10)` 修改 PTE 权限(支持 VMA 拆分)
|
||||
- [x] `mremap(25)`(`MREMAP_MAYMOVE` / `MREMAP_FIXED`)、`madvise(28)`
|
||||
- [x] 每进程 VMA 表(64 项),记录 base/size/prot/kind/flags
|
||||
- [x] SDK 的 `mmap` 把 `MAP_FAILED` 归一化为 0,既有 Explorer/devfs 调用方无需修改
|
||||
|
||||
验收:glibc 的 `malloc` 能使用 brk 主 arena;共享库文件可 mmap 后按段 mprotect;
|
||||
Explorer 的 framebuffer 映射不回退。
|
||||
|
||||
P2 已知限制:
|
||||
|
||||
- 文件映射是“读入页”,不支持 `MAP_SHARED` 回写/`msync`(ld.so 用 `MAP_PRIVATE`)
|
||||
- `PROT_NONE` 仍映射为 present(可读),没有 NX;`PROT_EXEC` 仅记录
|
||||
- `munmap` 只归还数据页,页表页仍留在 paging 池
|
||||
- `brk` 区不在 VMA 表里(glibc 不会对它 munmap)
|
||||
- `mremap` 增长必须带 `MREMAP_MAYMOVE`,通过“新建+拷贝+解映射”实现
|
||||
|
||||
### P3 — 进程、启动栈、解释器(本次完成)
|
||||
|
||||
- [x] 用户栈按 Linux 布局写入 `argc/argv/envp/auxv`
|
||||
(AT_PHDR/PHENT/PHNUM/PAGESZ/ENTRY/BASE/RANDOM/EXECFN/UID/EUID/GID/EGID 等)
|
||||
- [x] `execve(59)` 原型 `(path, argv, envp)`;SDK 保留 `spawn` 走私有 `SPAWN_PROC`
|
||||
- [x] `exit_group(231)` 终止进程内所有线程;`exit(60)` 只退当前线程
|
||||
- [x] `wait4(61)`(`WNOHANG`、状态字、子进程回收)、`getppid`
|
||||
- [x] `clone(56)`:`(flags, stack, ptid, ctid, tls)`;CLONE_VM 建线程,
|
||||
不带 CLONE_VM 时复制地址空间
|
||||
- [x] `fork(57)`:复制用户页 + 启动在父进程 syscall 返回点(RAX=0)
|
||||
- [x] `PT_INTERP` + ET_DYN 基址加载;`AT_BASE` 指向解释器
|
||||
- [x] 旧的 ViperOS `thread_create(func,arg)` 移到私有 `THREAD_CREATE_OLD`
|
||||
|
||||
验收:静态非 PIE、动态 PIE(安装 `ld.so` 与 libc)都可从正确的启动栈进入;
|
||||
fork 子进程在父进程同一返回点继续执行,父进程得到子 pid。
|
||||
|
||||
### P4 — TLS 与线程(本次完成)
|
||||
|
||||
- [x] `arch_prctl(158)`:`SET_FS/GET_FS`(`SET_GS/GET_GS` 返回 `-ENOSYS`)
|
||||
- [x] 线程切换保存/恢复 `IA32_FS_BASE`(独立表,不改 `Thread` 的 600B 布局)
|
||||
- [x] `rseq(334)` 返回 `-ENOSYS`;`set_robust_list` 记录
|
||||
- [x] `futex(202)`:`WAIT/WAKE` 采用“检查值 + sched_yield”轮询实现
|
||||
- [x] `clone(CLONE_VM|CLONE_SETTLS)`:子线程从 post-syscall RIP 开始,FS=tls
|
||||
- [x] `CLONE_CHILD_CLEARTID`:线程退出时写 0,配合 futex 唤醒 join
|
||||
|
||||
验收:`pthread_create/join` 走 Linux clone 路径;TLS 随线程切换。
|
||||
|
||||
### P5 — 时间、信号、IPC(本次完成)
|
||||
|
||||
- [x] `clock_gettime(228)` / `clock_getres(229)`(RTC 秒 + 1ms tick)
|
||||
- [x] `gettimeofday(96)`、`nanosleep(35)`
|
||||
- [x] `readv(19)` / `writev(20)`
|
||||
- [x] `pipe(22)` / `pipe2(293)`(8 个管道 × 4KB,轮询读写)
|
||||
- [x] `poll(7)`(当前固定返回 0 = 超时)
|
||||
- [x] `rt_sigaction(13)` / `rt_sigprocmask(14)` / `kill(62)`:完整登记
|
||||
- [x] 信号投递:syscall 返回前重写用户上下文,进入 handler;
|
||||
`rt_sigreturn(15)` 恢复原上下文与 syscall 返回值
|
||||
- [ ] `ppoll` / `select` / `epoll`
|
||||
|
||||
验收:`signal()`/`sigaction()` 注册的 handler 能在下一次 syscall 返回时执行;
|
||||
`raise()`/`kill(getpid(), sig)` 可触发。
|
||||
|
||||
### P6 — 清理私有段(部分完成)
|
||||
|
||||
- [x] `reboot(169)`:校验 Linux magic,支持 RESTART / POWER_OFF
|
||||
- [x] SDK 的 `process.reboot/shutdown` 改用 `reboot(169)`
|
||||
- [~] 私有 `LOAD_SO/SO_CALL1` 保留(内核启动仍加载 `slog.so`,用户态链接器未实现)
|
||||
- [~] 私有 `SPAWN_PROC` / `THREAD_CREATE_OLD` 保留(Terminal 与旧 SDK)
|
||||
- [~] 私有 `REBOOT/SHUTDOWN` 保留作为兼容别名
|
||||
- [ ] 用户态动态链接器 + 0x1000+ 段清空
|
||||
|
||||
验收:Linux `reboot` 可用;私有段尚未清零(受用户态加载器缺失限制)。
|
||||
|
||||
---
|
||||
|
||||
## 4. 调用迁移表
|
||||
|
||||
`P0` = 本次;`—` 表示尚未实现(内核统一返回 `-ENOSYS`)。
|
||||
|
||||
| 号 | Linux | ViperOS | 状态 | 备注 |
|
||||
|---:|---|---|---|---|
|
||||
| 0 | read | READ | P0 | 字节数 / `-errno` |
|
||||
| 1 | write | WRITE | P0 | 同上 |
|
||||
| 2 | open | OPEN | P0 | Linux `O_*`,内核翻译 `FA_*` |
|
||||
| 3 | close | CLOSE | P0 | 0 / `-EBADF` |
|
||||
| 4 | stat | STAT | P0 | 保留私有 `fileinfo`(兼容旧 SDK) |
|
||||
| 5 | fstat | FSTAT | P1 | `struct stat` |
|
||||
| 7 | poll | POLL | P5 | 固定返回 0(超时) |
|
||||
| 8 | lseek | SEEK | P0 | 返回新偏移 |
|
||||
| 9 | mmap | MMAP | P2 | 匿名/文件/设备三种;失败 `MAP_FAILED` |
|
||||
| 10 | mprotect | MPROTECT | P2 | |
|
||||
| 11 | munmap | MUNMAP | P2 | |
|
||||
| 12 | brk | BRK | P2 | |
|
||||
| 13 | rt_sigaction | RT_SIGACTION | P5 | 登记 + 投递 |
|
||||
| 14 | rt_sigprocmask | RT_SIGPROCMASK | P5 | 支持 block/unblock/setmask |
|
||||
| 15 | rt_sigreturn | RT_SIGRETURN | P5 | 恢复原上下文 |
|
||||
| 16 | ioctl | IOCTL | P0 | devfs 子集 |
|
||||
| 17 | pread64 | PREAD64 | P1 | |
|
||||
| 18 | pwrite64 | PWRITE64 | P1 | |
|
||||
| 19 | readv | READV | P5 | |
|
||||
| 20 | writev | WRITEV | P5 | |
|
||||
| 21 | access | ACCESS | P0 | |
|
||||
| 22 | pipe | PIPE | P5 | 8 × 4KB,轮询 |
|
||||
| 24 | sched_yield | YIELD | P0 | |
|
||||
| 25 | mremap | MREMAP | P2 | 增长需 `MREMAP_MAYMOVE` |
|
||||
| 28 | madvise | MADVISE | P2 | 空操作 |
|
||||
| 32 | dup | DUP | P1 | 末次 close 才释放对象 |
|
||||
| 33 | dup2 | DUP2 | P1 | |
|
||||
| 35 | nanosleep | NANOSLEEP | P5 | 1ms 精度 |
|
||||
| 39 | getpid | GETPID | P0 | |
|
||||
| 56 | clone | CLONE | P3 | Linux clone;CLONE_VM 建线程 |
|
||||
| 57 | fork | FORK | P3 | 复制用户地址空间 |
|
||||
| 59 | execve | SPAWN | P3 | 新进程 + 退出调用者 |
|
||||
| 60 | exit | THREAD_EXIT | P0 | |
|
||||
| 61 | wait4 | WAIT4 | P3 | 支持 WNOHANG |
|
||||
| 62 | kill | KILL | P5 | 待下次 syscall 投递 |
|
||||
| 63 | uname | UNAME | P0 | |
|
||||
| 72 | fcntl | FCNTL | P1 | |
|
||||
| 79 | getcwd | GETCWD | P0 | |
|
||||
| 80 | chdir | CHDIR | P0 | |
|
||||
| 82 | rename | RENAME | P1 | |
|
||||
| 83 | mkdir | MKDIR | P0 | |
|
||||
| 84 | rmdir | RMDIR | P1 | |
|
||||
| 87 | unlink | REMOVE | P0 | |
|
||||
| 89 | readlink | READLINK | P0 | 当前恒 `-EINVAL` |
|
||||
| 96 | gettimeofday | GETTIMEOFDAY | P5 | RTC 秒 |
|
||||
| 102 | getuid | GETUID | P0 | 恒 0 |
|
||||
| 104 | getgid | GETGID | P0 | 恒 0 |
|
||||
| 107 | geteuid | GETEUID | P0 | 恒 0 |
|
||||
| 108 | getegid | GETEGID | P0 | 恒 0 |
|
||||
| 110 | getppid | GETPPID | P0 | 恒 0 |
|
||||
| 158 | arch_prctl | ARCH_PRCTL | P4 | SET_FS/GET_FS |
|
||||
| 169 | reboot | REBOOT_LINUX | P6 | magic 校验;RESTART/POWER_OFF |
|
||||
| 186 | gettid | GETTID | P0 | 返回线程 tid |
|
||||
| 202 | futex | FUTEX | P4 | 轮询 WAIT/WAKE |
|
||||
| 217 | getdents64 | GETDENTS64 | P1 | 每次返回一条记录 |
|
||||
| 218 | set_tid_address | SET_TID_ADDRESS | P0 | |
|
||||
| 228 | clock_gettime | CLOCK_GETTIME | P5 | RTC/1ms tick |
|
||||
| 229 | clock_getres | CLOCK_GETRES | P5 | 1ms |
|
||||
| 231 | exit_group | EXIT | P3 | 终止进程内所有线程 |
|
||||
| 257 | openat | OPENAT | P1 | |
|
||||
| 262 | newfstatat | NEWFSTATAT | P1 | |
|
||||
| 263 | unlinkat | UNLINKAT | P1 | |
|
||||
| 267 | readlinkat | READLINKAT | P0 | 当前恒 `-EINVAL` |
|
||||
| 269 | faccessat | FACCESSAT | P0 | |
|
||||
| 273 | set_robust_list | SET_ROBUST_LIST | P0 | 仅记录 |
|
||||
| 292 | dup3 | DUP3 | P1 | flags 忽略 |
|
||||
| 293 | pipe2 | PIPE2 | P5 | flags 仅记录 |
|
||||
| 302 | prlimit64 | PRLIMIT64 | P0 | 只读限制 |
|
||||
| 318 | getrandom | GETRANDOM | P0 | 软件 DRNG |
|
||||
| 332 | statx | — | P1 | `-ENOSYS`,glibc 回退 |
|
||||
| 334 | rseq | RSEQ | P0 | `-ENOSYS` |
|
||||
| 0x1006 | — | LOAD_SO | P6 删除 | |
|
||||
| 0x1007 | — | SO_CALL1 | P6 删除 | |
|
||||
| 0x1008 | — | REBOOT | P6 保留别名 | |
|
||||
| 0x1009 | — | SHUTDOWN | P6 保留别名 | |
|
||||
| 0x100A | — | SPAWN_PROC | P6 保留 | Terminal `run` 用 |
|
||||
| 0x100B | — | THREAD_CREATE_OLD | P6 保留 | 旧 `thread_create(func,arg)` |
|
||||
|
||||
---
|
||||
|
||||
## 5. 测试与验收
|
||||
|
||||
1. **ABI 单元测试**(用户态小程序)
|
||||
- 每个调用至少覆盖成功 + 一个错误路径,断言返回值为 `-errno`
|
||||
- 结构体偏移/大小与 Linux 对照(编译期 `__sizeof__`)
|
||||
2. **`Scripts/syscall_table.py --check`**
|
||||
- CI/本地构建前检查两份表是否与权威表一致
|
||||
3. **glibc 里程碑**
|
||||
- M1:静态 `hello`(write/exit/brk/mmap/arch_prctl)
|
||||
- M2:动态 `hello`(`ld.so`、`openat`、`mmap`、`mprotect`)
|
||||
- M3:`pthread` + `malloc` 压力测试
|
||||
- M4:`ls`/`cat`/`sh` 等 coreutils
|
||||
4. **回归**
|
||||
- 现有 7 个应用(Terminal / Explorer / Scene3D / Gargantua / FontDemo / HelloWorld / ImageSee)必须继续运行
|
||||
|
||||
### 5.1 已完成的冒烟验证(2026-10-28,QEMU)
|
||||
|
||||
- 7 个内置应用全部启动,进入主循环,无异常
|
||||
- ImageSee 在同一启动中解码 PNG/JPEG 并在窗口显示(见 `docs/imagesee.md`)
|
||||
- 临时测试程序调用 `fork()`:父进程得到子 pid,子进程在同一返回点继续运行
|
||||
(`getpid/getppid` 正确),`wait4` 返回子 pid 且状态为 `0x700`(exit code 7)
|
||||
- 信号:`rt_sigaction(SIGUSR1)` + `kill(self)` → handler 在 `kill` 返回时执行,
|
||||
`kill` 仍返回 0;`SIGUSR2` 被 `rt_sigprocmask` 阻塞时不投递,解除阻塞后的下一次
|
||||
syscall 返回时投递
|
||||
- 无人值守运行:`python build.py --headless --runsecs=45`(`-display none`,
|
||||
45 秒后自动结束 QEMU,串口仍写入 `serial.log`)
|
||||
|
||||
---
|
||||
|
||||
## 6. 风险与已定决策
|
||||
|
||||
| 风险 | 处理 |
|
||||
|---|---|
|
||||
| 错误码改造影响旧应用 | SDK 已按 `<0` 判断;`FRESULT` 正数路径一并改掉,旧应用需回归测试 |
|
||||
| 两份表再次漂移 | 生成器 + `build.py` 前缀同步;禁止手改生成段 |
|
||||
| FAT32 无 inode/权限/符号链接 | `struct stat` 用固定值;`readlink` 一律 `-EINVAL`;`chmod` 后置 |
|
||||
| `mprotect` 未实现时 RELRO 失效 | P2 前在文档标注为“安全降级”,不假装成功 |
|
||||
| `getrandom` 无硬件熵 | 软件 xorshift + 启动期混合,仅用于 canary/非密码学场景 |
|
||||
| `uname` 报 Linux | 提升兼容性;`version` 字段保留 ViperOS 标识 |
|
||||
| 用户态栈布局改动大 | P3 单独提交,先静态后动态,避免与内存阶段交叉 |
|
||||
Reference in new issue
Block a user