Skip to content

rcore-os/tg-rcore-tutorial-ch6

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

106 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

第六章:文件系统

本章在第五章"进程管理"的基础上,引入了 文件系统 支持。用户程序不再嵌入内核镜像,而是存放在 磁盘镜像(fs.img)中,内核通过 VirtIO 块设备驱动easy-fs 文件系统 按名称加载和执行程序。同时,进程拥有了文件描述符表,可以通过 open/close/read/write 等标准接口操作文件。

通过本章的学习和实践,你将理解:

  • 什么是文件系统,为什么需要文件系统
  • easy-fs 的五层架构(块设备 → 块缓存 → 磁盘数据结构 → 磁盘管理器 → Inode)
  • 磁盘布局:SuperBlock、Inode Bitmap、Inode Area、Data Bitmap、Data Area
  • 文件描述符表和文件句柄的设计
  • VirtIO 块设备驱动的工作原理
  • open/close/read/write 系统调用的实现
  • 硬链接的概念和实现(练习题)

前置知识:建议先完成第一章至第五章的学习,理解裸机启动、Trap 处理、系统调用、多任务调度、虚拟内存和进程管理。

练习任务(以教代学,学以致用):

  • 学:读本文件,了解相关OS知识,在某个开发环境(在线或本地)中正确编译运行rcore-tutorial-ch6;根据本章的exercise.md完成作业练习。
  • 教:分析并改进rcore-tutorial-ch6的文档和代码,让自己更高效地完成本章学习。
  • 用:基于rcore-tutorial-ch6的源代码,实现用户态打砖块游戏应用,支持碰撞反弹、计分,及快捷键保存/恢复游戏进度等基本功能;并扩展操作系统内核功能,支持用户态打砖块游戏应用。demo

注:与AI充分合作,并保存与AI合作的交互过程,总结如何做到与AI合作提升自己的操作系统知识与能力。

项目结构

ch6/
├── .cargo/
│   └── config.toml     # Cargo 配置:交叉编译目标和 QEMU runner(含块设备参数)
├── .gitignore           # Git 忽略规则
├── build.rs            # 构建脚本:编译用户程序,打包 easy-fs 磁盘镜像
├── Cargo.toml          # 项目配置与依赖
├── LICENSE             # GPL v3 许可证
├── README.md           # 本文档
├── rust-toolchain.toml # Rust 工具链配置
├── test.sh             # 自动测试脚本
└── src/
    ├── main.rs         # 内核主体:初始化、调度循环、系统调用实现
    ├── fs.rs           # 文件系统管理:easy-fs 封装
    ├── process.rs      # 进程结构:含文件描述符表
    ├── processor.rs    # 处理器管理:进程管理器
    └── virtio_block.rs # VirtIO 块设备驱动

源码阅读导航索引

返回根文档导航总表

本章建议按“块设备 -> 文件系统 -> fd_table -> 文件 syscall”逐层阅读。

阅读顺序 文件 重点问题
1 src/virtio_block.rs VirtIO 驱动如何把块设备能力暴露给 easy-fs?
2 src/fs.rs FSopenread_all 如何构成“按文件加载程序”的路径?
3 src/process.rs 进程的 fd_table 如何初始化并在 fork 时继承?
4 src/main.rsimpls::IO open/read/write/close 如何经由 fd 映射到具体文件对象?
5 src/main.rskernel_space MMIO 映射为何是块设备可用的前提?

配套建议:结合 tg-rcore-tutorial-easy-fslayout/efs/vfs 注释阅读,能更完整理解“磁盘块 -> 文件语义”的抽象过程。

DoD 验收标准(本章完成判据)

  • 能说明“用户程序从内嵌镜像迁移到 fs.img”的核心变化
  • 能解释 VirtIO MMIO 映射为何是文件系统可用前提
  • 能从代码追踪 open/read/write/close 经 fd_table 到具体文件对象的路径
  • 能在 shell 中运行至少一个文件读写相关用户程序并解释结果
  • 能执行 ./test.sh base(练习时补充 ./test.sh exercise

概念-源码-测试三联表

核心概念 源码入口 自测方式(命令/现象)
块设备驱动接入 tg-rcore-tutorial-ch6/src/virtio_block.rs 启动日志出现 VirtIO MMIO 映射,文件系统可读写
文件系统封装 tg-rcore-tutorial-ch6/src/fs.rsFS/open/read_all initproc 能从文件系统成功加载
进程 fd 表 tg-rcore-tutorial-ch6/src/process.rsfd_table fork 后子进程可继承并使用已打开 fd
文件 syscall 实现 tg-rcore-tutorial-ch6/src/main.rsimpls::IO open/read/write/close 行为与期望一致

遇到构建/运行异常可先查看根文档的“高频错误速查表”。

一、环境准备

1.1 安装 Rust 工具链

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source "$HOME/.cargo/env"

验证:

rustc --version    # 要求 >= 1.85.0(支持 edition 2024)
cargo --version

1.2 添加 RISC-V 64 编译目标

rustup target add riscv64gc-unknown-none-elf

1.3 安装 QEMU 模拟器

Ubuntu / Debian:

sudo apt update
sudo apt install qemu-system-misc

macOS(Homebrew):

brew install qemu

验证:

qemu-system-riscv64 --version    # 建议 >= 7.0

1.4 安装额外工具

cargo install cargo-clone
cargo install cargo-binutils
rustup component add llvm-tools

1.5 获取源代码

方式一:只获取本实验

cargo clone tg-rcore-tutorial-ch6
cd tg-rcore-tutorial-ch6

方式二:获取所有实验

git clone --recurse-submodules https://github.com/rcore-os/tg-rcore-tutorial.git
cd tg-rcore-tutorial-ch6

二、编译与运行

2.1 编译

cargo build

编译过程与前几章类似,但 build.rs 有重要变化:

  1. 下载并编译 tg-rcore-tutorial-user 用户程序
  2. 不再将用户程序嵌入内核镜像,而是打包到 easy-fs 磁盘镜像 fs.img

环境变量说明:

  • TG_USER_DIR:指定本地 tg-rcore-tutorial-user 源码路径
  • TG_USER_VERSION:指定 tg-rcore-tutorial-user 版本(默认 0.2.0-preview.1
  • TG_SKIP_USER_APPS:跳过用户程序编译
  • LOG:设置日志级别

2.2 运行

基础模式:

cargo run

练习模式:

cargo run --features exercise

实际执行的 QEMU 命令等价于:

qemu-system-riscv64 \
    -machine virt \
    -nographic \
    -bios none \
    -drive file=target/riscv64gc-unknown-none-elf/debug/fs.img,if=none,format=raw,id=x0 \
    -device virtio-blk-device,drive=x0,bus=virtio-mmio-bus.0 \
    -kernel target/riscv64gc-unknown-none-elf/debug/tg-rcore-tutorial-ch6

注意与第五章不同:QEMU 命令中多了 -drive-device 参数,用于挂载 fs.img 磁盘镜像作为 VirtIO 块设备。

2.3 预期输出

[tg-rcore-tutorial-ch6 ...] Hello, world!
[ INFO] .text    ---> 0x80200000..0x8023xxxx
[ INFO] .rodata  ---> 0x8023xxxx..0x8024xxxx
[ INFO] .data    ---> 0x8024xxxx..0x81exxxxx
[ INFO] .boot    ---> 0x81exxxxx..0x81exxxxx
[ INFO] (heap)   ---> 0x81exxxxx..0x83200000
[ INFO] MMIO range -> 0x10001000..0x10002000

Rust user shell
>> ch5b_forktest_simple
...
Shell: Process 2 exited with code 0
>> 

与第五章不同,你会看到:

  • MMIO 地址范围的映射信息(VirtIO 块设备)
  • 用户程序从磁盘镜像(而非内核内嵌)加载和执行
  • Shell 交互功能与第五章相同

2.4 运行测试

./test.sh           # 运行全部测试(基础 + 练习)
./test.sh base      # 仅运行基础测试
./test.sh exercise  # 仅运行练习测试

三、操作系统核心概念

3.1 为什么需要文件系统?

在前几章中,用户程序直接嵌入内核镜像(通过 APP_ASMAPPS 表)。这存在明显的局限性:

问题 说明
耦合性 程序与内核绑定,修改用户程序需要重新编译内核
灵活性 无法在运行时动态创建、修改、删除文件
持久性 数据仅存在于内存中,关机后丢失
标准化 没有统一的文件操作接口(open/read/write/close)

文件系统 通过在磁盘上组织数据,解决了这些问题:

  • 程序和数据以文件形式存储在磁盘上
  • 内核通过文件系统接口访问磁盘
  • 提供标准的文件操作 API
  • 数据在重启后仍然存在

3.2 easy-fs 文件系统架构

easy-fs 是一个简化的类 UNIX inode 文件系统,采用五层架构:

┌─────────────────────────────────┐
│  第 5 层:Inode(虚拟文件系统)   │  文件/目录操作接口
│  find / create / read / write    │
├─────────────────────────────────┤
│  第 4 层:磁盘管理器              │  文件系统全局管理
│  EasyFileSystem                  │  inode/数据块分配
├─────────────────────────────────┤
│  第 3 层:磁盘数据结构            │  SuperBlock / DiskInode
│  Bitmap / DirEntry               │  DiskInode 索引结构
├─────────────────────────────────┤
│  第 2 层:块缓存                  │  BlockCache + CacheManager
│  缓存磁盘块到内存                 │  自动回写脏块
├─────────────────────────────────┤
│  第 1 层:块设备接口              │  BlockDevice trait
│  read_block / write_block        │  由 VirtIO 驱动实现
└─────────────────────────────────┘

3.3 磁盘布局

easy-fs 将磁盘划分为五个区域:

+------------+--------------+------------+-------------+-----------+
| SuperBlock | Inode Bitmap | Inode Area | Data Bitmap | Data Area |
+------------+--------------+------------+-------------+-----------+
   1 块        若干块          若干块        若干块         若干块
区域 作用
SuperBlock 文件系统元信息(魔数、总块数、各区域大小)
Inode Bitmap inode 分配位图,每 bit 对应一个 inode
Inode Area 存储 DiskInode(文件元数据:大小、类型、数据块索引)
Data Bitmap 数据块分配位图
Data Area 存储文件实际数据和目录项

DiskInode 索引结构(支持大文件):

DiskInode(128 字节)
├── 28 个直接索引块(每块 512 字节 → 14 KiB)
├── 1 个一级间接索引(128 个块 → 64 KiB)
└── 1 个二级间接索引(128 × 128 个块 → 8 MiB)
最大文件大小 ≈ 8 MiB + 64 KiB + 14 KiB

目录项(DirEntry,32 字节):

┌──────────────────┬──────────┐
│  文件名(28 字节) │ inode 号  │
│  含 '\0' 终止符    │  4 字节   │
└──────────────────┴──────────┘
每个 512 字节磁盘块可存储 16 个目录项

3.4 块缓存层

为了减少磁盘 I/O,easy-fs 使用块缓存(BlockCache):

程序读写请求
     │
     ▼
查找块缓存 ──命中──→ 直接读写内存缓冲区
     │
   未命中
     │
     ▼
从磁盘读取块到缓存 ──→ 读写内存缓冲区
     │
  缓存满时
     │
     ▼
淘汰最早的缓存块(若脏则回写磁盘)

块缓存的关键设计:

  • 每个缓存项包含 512 字节缓冲区 + 修改标记
  • 全局缓存管理器限制最大缓存数量
  • FIFO 淘汰策略
  • Drop 时自动回写脏块

3.5 VirtIO 块设备驱动

VirtIO 是 QEMU 使用的虚拟化 I/O 标准。在 tg-rcore-tutorial-ch6 中:

QEMU 宿主机
┌──────────────────────────────────┐
│  fs.img ──→ VirtIO 后端          │
│              ▲                    │
│              │ MMIO(0x10001000) │
│              ▼                    │
│  VirtIO 前端(Guest 内核驱动)     │
└──────────────────────────────────┘

内核需要:

  1. 在地址空间中映射 MMIO 地址 0x10001000
  2. 实现 Hal trait(DMA 内存分配、地址转换)
  3. 实现 BlockDevice trait,将 read_block/write_block 转发给 VirtIO 驱动

3.6 文件描述符表

本章为进程引入了文件描述符表(fd_table):

pub struct Process {
    pub fd_table: Vec<Option<Mutex<FileHandle>>>,
    // ... 其他字段
}

预留的标准文件描述符:

fd 名称 说明
0 stdin 标准输入(SBI console_getchar)
1 stdout 标准输出(SBI console_putchar)
2 stderr 标准错误(同 stdout)
3+ 普通文件 通过 open 系统调用分配

文件操作流程:

用户程序                    内核
   │                         │
   │── open("test.txt") ───→ │ 1. 地址翻译读取文件名
   │                         │ 2. easy-fs 查找/创建文件
   │                         │ 3. 分配 fd,插入 fd_table
   │←── 返回 fd = 3 ────────│
   │                         │
   │── write(3, buf, len) ──→│ 1. 查找 fd_table[3]
   │                         │ 2. 地址翻译获取用户缓冲区
   │                         │ 3. 通过 FileHandle 写入文件
   │←── 返回写入字节数 ──────│
   │                         │
   │── close(3) ────────────→│ 1. fd_table[3] = None
   │←── 返回 0 ─────────────│

3.7 系统调用

syscall ID 名称 功能
56 open 打开文件(新增
57 close 关闭文件描述符(新增
63 read 读取文件或标准输入(扩展:支持文件 fd)
64 write 写入文件或标准输出(扩展:支持文件 fd)
93 exit 退出进程
124 sched_yield 让出 CPU
113 clock_gettime 获取时间
172 getpid 获取 PID
214 sbrk 调整堆
220 fork 创建子进程(扩展:复制 fd_table)
221 exec 替换程序(变化:从文件系统加载)
260 wait 等待子进程
37 linkat 创建硬链接(练习题
35 unlinkat 删除链接(练习题
80 fstat 获取文件状态(练习题

3.8 从内嵌程序到文件系统加载

对比第五章和第六章的程序加载方式:

第五章:程序嵌入内核
────────────────────
build.rs 编译用户程序 → 生成 APP_ASM → 嵌入内核镜像
exec 时:APPS.get(name) → 内存中的 ELF 数据

第六章:程序存储在文件系统
────────────────────────
build.rs 编译用户程序 → 打包到 fs.img → QEMU 挂载为块设备
exec 时:FS.open(name) → read_all() → 从磁盘读取 ELF 数据

四、代码解读

4.1 src/main.rs —— 内核主体

启动流程(与第五章类似,新增 MMIO 映射):

  1. 清零 BSS 段 → 初始化控制台 → 初始化堆
  2. 创建异界传送门 → 建立内核地址空间
  3. 新增:映射 VirtIO MMIO 地址 0x10001000
  4. 初始化系统调用 → 从文件系统加载 initproc → 进入调度循环

IO 系统调用的变化:

  • write/read:先检查是否为标准 I/O fd,否则通过 fd_table 查找文件句柄读写
  • open:从用户空间读取文件路径字符串 → easy-fs 打开文件 → 分配 fd
  • close:将 fd_table 对应项设为 None
  • exec:从 FS.open(name) + read_all() 加载 ELF,而非 APPS.get(name)

4.2 src/fs.rs —— 文件系统管理

FS:全局文件系统实例,通过 BLOCK_DEVICE(VirtIO)打开 easy-fs

FileSystem 实现 FSManager trait:

  • open():支持 CREATE(创建)、TRUNC(清空)等标志
  • find():在根目录中查找文件
  • readdir():列出所有文件名
  • read_all():辅助函数,读取整个文件内容

4.3 src/process.rs —— 进程管理

与第五章相比新增 fd_table 字段:

  • from_elf():初始化时预留 fd 0/1/2
  • fork():深拷贝父进程的 fd_table(子进程继承已打开文件)
  • exec():保留 fd_table 不变

4.4 src/virtio_block.rs —— VirtIO 驱动

  • BLOCK_DEVICE:全局块设备实例
  • VirtIOBlock:封装 virtio-drivers 库的 VirtIOBlk
  • VirtioHal:DMA 内存分配和地址转换(恒等映射下很简单)

4.5 Cargo.toml —— 依赖说明

依赖 说明
virtio-drivers VirtIO 设备驱动库(本章新增
tg-rcore-tutorial-easy-fs easy-fs 文件系统实现(本章新增
xmas-elf ELF 文件解析
riscv RISC-V CSR 寄存器访问
spin 自旋锁(Lazy、Mutex)
tg-rcore-tutorial-sbi SBI 调用封装
tg-rcore-tutorial-linker 链接脚本和内核布局
tg-rcore-tutorial-console 控制台输出和日志
tg-rcore-tutorial-kernel-context 用户上下文及异界传送门
tg-rcore-tutorial-kernel-alloc 内核堆分配器
tg-rcore-tutorial-kernel-vm 虚拟内存管理
tg-rcore-tutorial-syscall 系统调用定义与分发
tg-rcore-tutorial-task-manage 进程管理框架

五、编程练习

5.1 硬链接

硬链接要求两个不同的目录项指向同一个文件,在我们的文件系统中也就是两个不同名称目录项指向同一个磁盘块。

本节要求实现三个系统调用 linkatunlinkatfstat

linkat

fn linkat(&self, _caller: Caller, _olddirfd: i32, oldpath: usize,
          _newdirfd: i32, newpath: usize, _flags: u32) -> isize
  • 参数:
    • olddirfd, newdirfd: 仅为兼容性考虑,始终为 AT_FDCWD (-100),可忽略
    • flags: 仅为兼容性考虑,始终为 0,可忽略
    • oldpath:原有文件路径
    • newpath: 新的链接文件路径
  • 说明:
    • 不考虑新文件路径已存在的情况(属于未定义行为)
    • 新旧名字一致时返回 -1
  • 返回值:成功 0,错误 -1

unlinkat

fn unlinkat(&self, _caller: Caller, _dirfd: i32, path: usize, _flags: u32) -> isize
  • 参数:
    • dirfd: 始终为 AT_FDCWD (-100),可忽略
    • flags: 始终为 0,可忽略
    • path:文件路径
  • 说明:使用 unlink 彻底删除文件时,需要回收 inode 及其数据块
  • 返回值:成功 0,错误 -1
  • 可能的错误:文件不存在

fstat

  • syscall ID: 80
  • 功能:获取文件状态
fn fstat(&self, _caller: Caller, fd: usize, st: usize) -> isize
  • 参数:
    • fd: 文件描述符
    • st: 文件状态结构体指针
#[repr(C)]
pub struct Stat {
    pub dev: u64,        // 磁盘驱动器号(写死为 0)
    pub ino: u64,        // inode 编号
    pub mode: StatMode,  // 文件类型(FILE 或 DIR)
    pub nlink: u32,      // 硬链接数量(初始为 1)
    pad: [u64; 7],
}

bitflags! {
    pub struct StatMode: u32 {
        const NULL  = 0;
        const DIR   = 0o040000;   // 目录
        const FILE  = 0o100000;   // 普通文件
    }
}

5.2 实现提示

  • linkatunlinkat 的文件路径读取可参考 src/main.rsopen 系统调用的实现
  • fstat 的 Stat 结构体写入可参考 clock_gettime 对 TimeSpec 的写入方式(地址翻译后写入)
  • 需要拉取 tg-rcore-tutorial-easy-fs 到本地并修改以支持硬链接:
    cd tg-rcore-tutorial-ch6
    cargo clone tg-rcore-tutorial-easy-fs
    然后修改 Cargo.toml
    [dependencies]
    tg-rcore-tutorial-easy-fs = { path = "./tg-rcore-tutorial-easy-fs" }

5.3 实验要求

目录结构:

tg-rcore-tutorial-ch6/
├── Cargo.toml(需要修改依赖配置)
├── src/(需要修改)
│   ├── main.rs
│   ├── fs.rs
│   ├── process.rs
│   ├── processor.rs
│   └── virtio_block.rs
├── tg-rcore-tutorial-easy-fs/(需拉取到本地并修改以支持硬链接)
│   └── src/
└── tg-rcore-tutorial-user/(自动拉取,无需修改)

运行和测试:

cargo run --features exercise    # 运行练习测例
./test.sh exercise               # 测试练习测例

然后在终端中输入 tg-rcore-tutorial-ch6_usertest 运行所有练习测例。

前向兼容:你的内核必须前向兼容,需要能通过前一章的所有测例。


六、本章小结

通过本章的学习和实践,你完成了操作系统中的重要基础设施——文件系统:

  1. 文件系统概念:通过 easy-fs 理解了 inode 文件系统的基本原理
  2. 五层架构:块设备接口 → 块缓存 → 磁盘数据结构 → 磁盘管理器 → Inode
  3. 磁盘布局:SuperBlock、Bitmap、Inode Area、Data Area 的组织方式
  4. VirtIO 驱动:通过 MMIO 访问虚拟块设备,连接文件系统与磁盘
  5. 文件描述符表:统一管理标准 I/O 和普通文件的抽象
  6. 文件操作接口:open/close/read/write 系统调用的实现
  7. 程序加载方式的变化:从内核内嵌到文件系统动态加载

在后续章节中,我们将在文件系统的基础上引入进程间通信(管道等)机制。

七、思考题

  1. 为什么需要块缓存? 如果每次读写都直接访问磁盘,性能会怎样?块缓存的淘汰策略(FIFO vs LRU)对性能有什么影响?

  2. DiskInode 的索引设计? 为什么 easy-fs 的 DiskInode 使用直接 + 一级间接 + 二级间接的三级索引结构?如果只有直接索引,最大文件大小是多少?

  3. 文件描述符表的继承? fork 时子进程复制了父进程的 fd_table。如果父进程打开了一个文件然后 fork,父子进程写入同一个文件会发生什么?

  4. 硬链接 vs 软链接? 硬链接和软链接有什么区别?为什么硬链接不能跨文件系统?删除一个硬链接后,文件何时真正被删除?

  5. exec 后的 fd_table? 本实现中 exec 不清除 fd_table。这意味着什么?UNIX 系统中 exec 如何处理文件描述符(提示:close-on-exec 标志)?

参考资料


附录:rCore-Tutorial 组件分析表

表 1:tg-rcore-tutorial-ch1 ~ tg-rcore-tutorial-ch8 操作系统内核总体情况描述表

操作系统内核 所涉及核心知识点 主要完成功能 所依赖的组件
tg-rcore-tutorial-ch1 应用程序执行环境
裸机编程(Bare-metal)
SBI(Supervisor Binary Interface)
RISC-V 特权级(M/S-mode)
链接脚本(Linker Script)
内存布局(Memory Layout)
Panic 处理
最小 S-mode 裸机程序
QEMU 直接启动(无 OpenSBI)
打印 "Hello, world!" 并关机
演示最基本的 OS 执行环境
tg-rcore-tutorial-sbi
tg-rcore-tutorial-ch2 批处理系统(Batch Processing)
特权级切换(U-mode ↔ S-mode)
Trap 处理(ecall / 异常)
上下文保存与恢复
系统调用(write / exit)
用户态 / 内核态
sret 返回指令
批处理操作系统
顺序加载运行多个用户程序
特权级切换和 Trap 处理框架
实现 write / exit 系统调用
tg-rcore-tutorial-sbi
tg-rcore-tutorial-linker
tg-rcore-tutorial-console
tg-rcore-tutorial-kernel-context
tg-rcore-tutorial-syscall
tg-rcore-tutorial-ch3 多道程序(Multiprogramming)
任务控制块(TCB)
协作式调度(yield)
抢占式调度(Preemptive)
时钟中断(Clock Interrupt)
时间片轮转(Time Slice)
任务切换(Task Switch)
任务状态(Ready/Running/Finished)
clock_gettime 系统调用
多道程序与分时多任务
多程序同时驻留内存
协作式 + 抢占式调度
时钟中断与时间管理
tg-rcore-tutorial-sbi
tg-rcore-tutorial-linker
tg-rcore-tutorial-console
tg-rcore-tutorial-kernel-context
tg-rcore-tutorial-syscall
tg-rcore-tutorial-ch4 虚拟内存(Virtual Memory)
Sv39 三级页表(Page Table)
地址空间隔离(Address Space)
页表项(PTE)与标志位
地址转换(VA → PA)
异界传送门(MultislotPortal)
ELF 加载与解析
堆管理(sbrk)
恒等映射(Identity Mapping)
内存保护(Memory Protection)
satp CSR
引入 Sv39 虚拟内存
每个用户进程独立地址空间
跨地址空间上下文切换
进程隔离和内存保护
tg-rcore-tutorial-sbi
tg-rcore-tutorial-linker
tg-rcore-tutorial-console
tg-rcore-tutorial-kernel-context
tg-rcore-tutorial-kernel-alloc
tg-rcore-tutorial-kernel-vm
tg-rcore-tutorial-syscall
tg-rcore-tutorial-ch5 进程(Process)
进程控制块(PCB)
进程标识符(PID)
fork(地址空间深拷贝)
exec(程序替换)
waitpid(等待子进程)
进程树 / 父子关系
初始进程(initproc)
Shell 交互式命令行
进程生命周期(Ready/Running/Zombie)
步幅调度(Stride Scheduling)
引入进程管理
fork / exec / waitpid 系统调用
动态创建、替换、等待进程
Shell 交互式命令行
tg-rcore-tutorial-sbi
tg-rcore-tutorial-linker
tg-rcore-tutorial-console
tg-rcore-tutorial-kernel-context
tg-rcore-tutorial-kernel-alloc
tg-rcore-tutorial-kernel-vm
tg-rcore-tutorial-syscall
tg-rcore-tutorial-task-manage
tg-rcore-tutorial-ch6 文件系统(File System)
easy-fs 五层架构
SuperBlock / Inode / 位图
DiskInode(直接+间接索引)
目录项(DirEntry)
文件描述符表(fd_table)
文件句柄(FileHandle)
VirtIO 块设备驱动
MMIO(Memory-Mapped I/O)
块缓存(Block Cache)
硬链接(Hard Link)
open / close / read / write 系统调用
引入文件系统与 I/O
用户程序存储在磁盘镜像(fs.img)
VirtIO 块设备驱动
easy-fs 文件系统实现
文件打开 / 关闭 / 读写
tg-rcore-tutorial-sbi
tg-rcore-tutorial-linker
tg-rcore-tutorial-console
tg-rcore-tutorial-kernel-context
tg-rcore-tutorial-kernel-alloc
tg-rcore-tutorial-kernel-vm
tg-rcore-tutorial-syscall
tg-rcore-tutorial-task-manage
tg-rcore-tutorial-easy-fs
tg-rcore-tutorial-ch7 进程间通信(IPC)
管道(Pipe)
环形缓冲区(Ring Buffer)
统一文件描述符(Fd 枚举)
信号(Signal)
信号集(SignalSet)
信号屏蔽字(Signal Mask)
信号处理函数(Signal Handler)
kill / sigaction / sigprocmask / sigreturn
命令行参数(argc / argv)
I/O 重定向(dup)
进程间通信-管道
异步事件通知(信号)
统一文件描述符抽象
信号发送 / 注册 / 屏蔽 / 返回
tg-rcore-tutorial-sbi
tg-rcore-tutorial-linker
tg-rcore-tutorial-console
tg-rcore-tutorial-kernel-context
tg-rcore-tutorial-kernel-alloc
tg-rcore-tutorial-kernel-vm
tg-rcore-tutorial-syscall
tg-rcore-tutorial-task-manage
tg-rcore-tutorial-easy-fs
tg-rcore-tutorial-signal
tg-rcore-tutorial-signal-impl
tg-rcore-tutorial-ch8 同步互斥(Sync&Mutex)
线程(Thread)/ 线程标识符(TID)
进程-线程分离
竞态条件(Race Condition)
临界区(Critical Section)
互斥(Mutual Exclusion)
互斥锁(Mutex:自旋锁 vs 阻塞锁)
信号量(Semaphore:P/V 操作)
条件变量(Condvar)
管程(Monitor:Mesa 语义)
线程阻塞与唤醒(wait queue)
死锁(Deadlock)/ 死锁四条件
银行家算法(Banker's Algorithm)
双层管理器(PThreadManager)
进程-线程分离
同一进程内多线程并发
互斥锁(MutexBlocking)
信号量(Semaphore)
条件变量(Condvar)
线程阻塞与唤醒机制
死锁检测(练习)
tg-rcore-tutorial-sbi
tg-rcore-tutorial-linker
tg-rcore-tutorial-console
tg-rcore-tutorial-kernel-context
tg-rcore-tutorial-kernel-alloc
tg-rcore-tutorial-kernel-vm
tg-rcore-tutorial-syscall
tg-rcore-tutorial-task-manage
tg-rcore-tutorial-easy-fs
tg-rcore-tutorial-signal
tg-rcore-tutorial-signal-impl
tg-rcore-tutorial-sync

表 2:tg-rcore-tutorial-ch1 ~ tg-rcore-tutorial-ch8 操作系统内核所依赖组件总体情况描述表

功能组件 所涉及核心知识点 主要完成功能 所依赖的组件
tg-rcore-tutorial-sbi SBI(Supervisor Binary Interface)
console_putchar / console_getchar
系统关机(shutdown)
RISC-V 特权级(M/S-mode)
ecall 指令
S→M 模式的 SBI 调用封装
字符输出 / 字符读取
系统关机
支持 nobios 直接操作 UART
tg-rcore-tutorial-console 控制台 I/O
格式化输出(print! / println!)
日志系统(Log Level)
自旋锁保护的全局控制台
可定制 print! / println! 宏
log::Log 日志实现
Console trait 抽象底层输出
tg-rcore-tutorial-kernel-context 上下文(Context)
Trap 帧(Trap Frame)
寄存器保存与恢复
特权级切换
stvec / sepc / scause CSR
LocalContext(本地上下文)
ForeignContext(跨地址空间上下文)
异界传送门(MultislotPortal)
用户/内核态切换上下文管理
LocalContext 结构
ForeignContext(含 satp)
MultislotPortal 跨地址空间执行
tg-rcore-tutorial-kernel-alloc 内核堆分配器
伙伴系统(Buddy Allocation)
动态内存管理
#[global_allocator]
基于伙伴算法的 GlobalAlloc
堆初始化(init)
物理内存转移(transfer)
tg-rcore-tutorial-kernel-vm 虚拟内存管理
页表(Page Table)
Sv39 分页(三级页表)
虚拟地址(VAddr)/ 物理地址(PAddr)
虚拟页号(VPN)/ 物理页号(PPN)
页表项(PTE)/ 页表标志位(VmFlags)
地址空间(AddressSpace)
PageManager trait
地址翻译(translate)
Sv39 页表管理
AddressSpace 地址空间抽象
虚实地址转换
页面映射(map / map_extern)
页表项操作
tg-rcore-tutorial-syscall 系统调用(System Call)
系统调用号(SyscallId)
系统调用分发(handle)
系统调用结果(Done / Unsupported)
Caller 抽象
IO / Process / Scheduling / Clock /
Signal / Thread / SyncMutex trait 接口
系统调用 ID 与参数定义
trait 接口供内核实现
init_io / init_process / init_scheduling /
init_clock / init_signal /
init_thread / init_sync_mutex
支持 kernel / user feature
tg-rcore-tutorial-signal-defs
tg-rcore-tutorial-task-manage 任务管理(Task Management)
调度(Scheduling)
进程管理器(PManager, proc feature)
双层管理器(PThreadManager, thread feature)
ProcId / ThreadId
就绪队列(Ready Queue)
Manage trait / Schedule trait
进程等待(wait / waitpid)
线程等待(waittid)
阻塞与唤醒(blocked / re_enque)
Manage 和 Schedule trait 抽象
proc feature:单层进程管理器(PManager)
thread feature:双层管理器(PThreadManager)
进程树 / 父子关系
线程阻塞 / 唤醒
tg-rcore-tutorial-easy-fs 文件系统(File System)
SuperBlock / Inode / 位图(Bitmap)
DiskInode(直接+间接索引)
块缓存(Block Cache)
BlockDevice trait
文件句柄(FileHandle)
打开标志(OpenFlags)
管道(Pipe)/ 环形缓冲区
用户缓冲区(UserBuffer)
FSManager trait
easy-fs 五层架构实现
文件创建 / 读写 / 目录操作
块缓存管理
管道环形缓冲区实现
FSManager trait 抽象
tg-rcore-tutorial-signal-defs 信号编号(SignalNo)
SIGKILL / SIGINT / SIGUSR1 等
信号动作(SignalAction)
信号集(SignalSet)
最大信号数(MAX_SIG)
信号编号枚举定义
信号动作结构定义
信号集类型定义
为 tg-rcore-tutorial-signal 和 tg-rcore-tutorial-syscall 提供共用类型
tg-rcore-tutorial-signal 信号处理(Signal Handling)
Signal trait 接口
add_signal / handle_signals
get_action_ref / set_action
update_mask / sig_return / from_fork
SignalResult(Handled / ProcessKilled)
Signal trait 接口定义
信号添加 / 处理 / 动作设置
屏蔽字更新 / 信号返回
fork 继承
tg-rcore-tutorial-kernel-context
tg-rcore-tutorial-signal-defs
tg-rcore-tutorial-signal-impl SignalImpl 结构
已接收信号位图(received)
信号屏蔽字(mask)
信号处理中状态(handling)
信号动作表(actions)
信号处理函数调用
上下文保存与恢复
Signal trait 的参考实现
信号接收位图管理
屏蔽字逻辑
处理状态和动作表
tg-rcore-tutorial-kernel-context
tg-rcore-tutorial-signal
tg-rcore-tutorial-sync 互斥锁(Mutex trait: lock / unlock)
阻塞互斥锁(MutexBlocking)
信号量(Semaphore: up / down)
条件变量(Condvar: signal / wait_with_mutex)
等待队列(VecDeque<ThreadId>)
UPIntrFreeCell
MutexBlocking 阻塞互斥锁
Semaphore 信号量
Condvar 条件变量
通过 ThreadId 与调度器交互
tg-rcore-tutorial-task-manage
tg-rcore-tutorial-user 用户态程序(User-space App)
用户库(User Library)
系统调用封装(syscall wrapper)
用户堆分配器
用户态 print! / println!
用户测试程序运行时库
系统调用封装
用户堆分配器
各章节测试用例(ch2~ch8)
tg-rcore-tutorial-console
tg-rcore-tutorial-syscall
tg-rcore-tutorial-checker 测试验证
输出模式匹配
正则表达式(Regex)
测试用例判定
rCore-Tutorial CLI 测试输出检查工具
验证内核输出匹配预期模式
支持 --ch N 和 --exercise 模式
tg-rcore-tutorial-linker 链接脚本(Linker Script)
内核内存布局(KernelLayout)
.text / .rodata / .data / .bss / .boot 段
入口点(boot0! 宏)
BSS 段清零
形成内核空间布局的链接脚本模板
用于 build.rs 工具构建 linker.ld
内核布局定位(KernelLayout::locate)
入口宏(boot0!)
段信息迭代

License

Licensed under GNU GENERAL PUBLIC LICENSE, Version 3.0.

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors