Skip to content

导引:点亮什么与为什么

003 在内核里搭好了整套 VFS:挂载表、inode、文件描述符表、ramdisk 后端。但那间房没开门——用户态的程序碰不到它,因为还没有「打开文件」「读文件」的系统调用。这一篇(003 的下半)就是给 VFS 装门:把 open/read/write/close/getdents 这些系统调用接到 VFS 管线上,再在用户态 libc 里包一层薄壳,最后让 shell 长出 catls 两个命令。完成后,你就能在 shell 里敲 cat hello.txt 看到文件内容、敲 ls 列出目录——VFS 真正被人用上了。

这一章我们要点亮什么

把 003 那套「内核内部 VFS」暴露给用户态,形成一条完整的「用户程序 → 系统调用 → VFS → 文件」链路。三件事:

第一,系统调用层:实现 sys_open(路径解析 → inode → 分配 fd)、sys_read/sys_write(通过 fd 找 File、调 inode 的操作)、sys_closesys_getdents(列目录),把它们接进 023 那套 syscall 派发表。

第二,用户态封装:libc 里给每个系统调用写一个薄薄的汇编包装(就是一句 syscall 指令加参数装载),让用户程序像调普通函数一样 sys_open(...)

第三,shell 落地:cat(open + 循环 read + 往 stdout write)和 ls(open 目录 + 循环 getdents)两个命令,把前面两件事串成一个用户能敲的命令。

验收点很直观:进 shell 敲 cat hello.txt,看到 Hello from Cinux!;敲 ls,看到文件清单。这两条能跑,说明从用户键盘到 VFS 到 ramdisk 的整条链路通了。

为什么现在需要它

为什么紧接 003。003 把 VFS 装修好了,但 VFS 的入口在内核里,用户态够不着。系统调用就是那扇门——它是用户态进入内核态的唯一正门(023 已经搭好了 syscall 指令和派发框架)。这一篇要做的是:在这扇门后面接上通往 VFS 的走廊。

为什么要把 read/write 也改。023/024 那会儿,sys_write 是直接往串口/屏幕写的、sys_read(fd=0)是直接读键盘的——它们没经过任何「文件」抽象。现在有了 VFS,read/write 就该统一走「fd → File → inode 操作」这条路:你 write 到 fd 1(stdout)还是 write 到一个打开的普通文件,用的是同一套机制(只是底层 inode 的操作不同)。这一篇把 read/write 收编进 VFS 框架,顺带保留 fd 0(stdin)读键盘的老路(下面解释为什么)。

还有一笔关于「用户传进来的指针」的账。系统调用的参数里有用户态地址(比如 open(path,...) 的 path 指针、read(fd,buf,...) 的 buf 指针)。内核不能盲目信用户传的地址——用户可能传个空指针、或传个内核地址企图让内核替它读内核内存。所以每个收地址的系统调用,都得先做「这个地址合法吗」的检查。这一篇用 x86-64 的「规范地址」规则来卡这道关,是系统调用安全的基本功。

035_multi_terminal-45-gf25de18 · f25de18 · 2026-08-04