Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"server": "hexo server"
},
"hexo": {
"version": "7.0.0"
"version": "4.2.1"
},
"dependencies": {
"hexo": "^4.2.1",
Expand All @@ -24,4 +24,4 @@
"hexo-renderer-stylus": "^1.1.0",
"hexo-server": "^1.0.0"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
---
title: 2025秋冬季开源操作系统训练营前三阶段总结-PassingThroughStarDust
date: 2025-11-15 19:17:45
tags:
- author:余泽铖
---
# 2025年秋冬季开源操作系统训练营总结

## 基础阶段 - Rust 编程

我在初次接触 Rust 的时候已经有 C/C++ 编程基础,但出于谨慎(那会还是个懵懂的计算机新人,对很多新事物的学习抱着敬畏之心,学习的时候生怕因为少看资料而错过重点),我一边阅读 Rust 官方的 [The Rust Programming Language](https://doc.rust-lang.org/stable/book/) 一边完成基础阶段的 rustlings 习题(后来才发觉这样太慢了,很多内容根本没必要先看书,直接上手做题就懂了,还有些东西在没有具备相关领域知识前光靠看语法书很难理解它的设计目的和应用场景,与其看书不如先学着怎么写出代码)。

不过即使如此谨慎,我还是没能一劳永逸 —— 在经过前面的 100 道语法基础题的“呵护”以后,最后的 10 道算法题对我进行了惨无人道的折磨......这并非是我不懂那些数据结构与算法,而是 Rust 各种语法规则限制让我不停地卡在编译错误上,幸好自己最后还是坚持下来把所有题目都做完了,自己对 Rust 的语法特点也有了一个较为初步的认识。

## 专业阶段 - OS 设计与实现

在专业阶段中我以[rCore-Tutorial-Book](https://rcore-os.cn/rCore-Tutorial-Book-v3/index.html)这本书为主线,一章一章地跟着学习。因为我之前没有学过操作系统、计算机组成原理,我出于保险起见认真地学习了书中的所有内容,并补了一些相关知识,所以我在第二阶段花了不少时间。

### 第 1 章

在学习第 1 章时,由于所需知识过多,我倍感困难。因此我一步步按照第一章的步骤自己实现了 LibOS ,期间又看了训练营导学阶段页面上的前几节基础课和部分中科院软件所PLCT实验室的网课[《循序渐进,学习开发一个RISC-V上的操作系统》](https://www.bilibili.com/video/BV1Q5411w7z5/)来补充基础的操作系统概念和RISC-V汇编的知识,对实在记不住的地方我直接记笔记梳理思维导图。就这样我才跌跌撞撞地完全理解了第 1 章。

### 第 2 章

第 2 章因为书中只提供了代码切片,没法一步步做了,不过我找到了 [rCore-Tutorial-Book 对应的代码仓库](https://github.com/rcore-os/rCore-Tutorial-v3),于是根据书上的讲解,我按操作系统在启动以后的执行顺序一步步地阅读了源代码,彻底理解了整一章的内容。总的来说,因为在第 1 章开了个好头,所以第 2 章的压力稍微小了一点。

### 第 3 章( lab1 )

第 3 章是对第 2 章在同一功能(多任务处理)上的升级,理解起来不是太难,我按照学习第 2 阶段的方法,在阅读完整个章节后又阅读一遍源码,后面很自然地知道了 lab1 应该在哪里添加修改。

### 第 4 章( lab2 )

第 4 章中关于页表机制的东西有点太多了,按照前 3 章的学习方法我在这里浪费了大量的时间,主要因为第 4 章的代码切片讲解太多,我很难把它们全都联系起来。在第 4 章后我决定先看项目源码,梳理下整个项目结构,包括每个文件有哪些函数和全局变量后再看书。

实验难度还行,但中间因为 rCore 的 find_pte 函数的设计有一个小漏洞,导致我的代码没有按照预期执行,我花了很长时间去排错,最后靠打印出相关的物理页号才锁定了这个漏洞。这个漏洞具体为:

``` rust
// os/src/mm/page_table.rs
fn find_pte(&self, vpn: VirtPageNum) -> Option<&mut PageTableEntry> {
let idxs = vpn.indexes();
let mut ppn = self.root_ppn;
let mut result: Option<&mut PageTableEntry> = None;
for (i, idx) in idxs.iter().enumerate() {
let pte = &mut ppn.get_pte_array()[*idx];
// -- Fixing Part Start --
// 这里是修改后的代码,调换了两个 if 块的顺序。
if !pte.is_valid() {
return None;
}
if i == 2 {
result = Some(pte);
break;
}
// 原来的代码。后置 is_valid 判断会导致返回非 valid 的 PTE
/*
if i == 2 {
result = Some(pte);
break;
}
if !pte.is_valid() {
return None;
}
*/
// -- Fixing Part End --
ppn = pte.ppn();
}
result
}
```


### 第 5 章( lab3 )

在学习第 5 章时我按照第 4 章总结的经验先快速梳理了代码结构,因此阅读起来较为轻松,实验也比较简单,很快就完成了。

### 第 6 章( lab4 )

因为第 6 章内容太多,又因为引入了文件系统,项目代码过于庞大,我花了大量的时间来理解整个过程,但到做完实验我都没有对整个项目有一个清晰的思维构图,后面我借助 AI 进行章节总结并向它就一些细节提问才建立起了完整的认知。

完成 lab4 是较为困难的,主要是因为很难 debug 在 easy-fs 这个外部 crate 中修改时产生的错误,我那会又想加快速度而没有去琢磨如何使用 gdb 和 log crate 。后来是靠着一点点地梳理自己添加修改的地方的逻辑,找出来其中的错误(也即充分理解了计算机工程先驱者们开发 gdb 和 log crate这类工具的初衷)。比较好玩的是我犯的错都是数值上的错误,比如数值索引、循环次数控制,这应该是因为连续熬夜看基础知识导致大脑困倦了(我刚开始怎么也找不到错误,中间休息了3天后返回去看代码才发现了一堆数值错误)。

### 第 7 章( lab5 )

从第 7 章开始因为项目实在过于庞大,我不再像之前那样一步步地看整个项目源代码了。通过 AI 辅助总结我的阅读速度快了不少,很快就理解了管道的机制。因为 lab5 没有安排代码作业,所以还是轻松的。

### 第 8 章( lab6 )

第 8 章的理论学习也在 AI 的辅助下快速完成了。但对于 lab6 ,我在刚开始还是很困惑的,因为银行家算法的设计前提是已知各任务的最大资源需求量,这与现代操作系统的特点不符(查了一下资料,在提出银行家算法时主流操作系统都还是批处理系统,算法就是根据它的特点来设计的)。后来我通过只关注单次分配的安全性找到了设计思路。不过开始时我为了偷懒(不想去搞一个专门的全局数据结构),只在每次需要死锁检查时才生成算法需要的矩阵(觉得每次allocation矩阵为空影响不大),但测试集以结果错误“认可了”我的偷懒(不过我刚开始认为我的思路没有问题)。最终,我还是老老实实地维护了一个全局的数据结构才通过测试。

## 项目基础阶段 - 组件化操作系统

有了 rCore 的基础,理解 arceos 的设计不是太困难,但因为项目规模太大了,我出于时间考虑把重心放在完成练习上而不是理解项目结构。有点头疼的是实验提供的文档没有完成,部分内容也已经过时,所以对完成练习并没有太多帮助。以下是我对所有练习的总结:

### print_with_color

没啥难的,在 rCore-Tutorial-Book 的课后练习中介绍了 ANSI 转义字符,直接添加到 println macro 的实现中即可。ANSI 的转义字符介绍在:

## support_hashmap

查阅了一些关于 hash map 的介绍很快完成了基本的 hash map 架构。

## alt_alloc

实现逻辑不难。有意思的是在完成后我根据 VSCode Copilot 的提示,使用了复杂的如 saturating_add 、 wrapping_add 这样的封装函数代替原本简单的运算符,结果原本可以通过测试的逻辑没有通过,从这里开始我觉得还是有必要遵循“大道至简”,不要刻意使用没见过的复杂新奇功能。

## ramfs_rename

实现逻辑也不难,但因为不是很熟悉代码的结构,在 rename 函数的实现中对 src_path 和 dst_path 的有效性验证都是默认从“ / ”目录开始,结果一直无法通过测试。最后在 Copilot 的帮助下理清了 rename 在调用之前发生的事情,发现当 ramfs 被挂在到主文件系统中后,传给它的路径参数会被修建,只保留 ramfs 根节点开始的部分, 也即 rename 的 src_path 参数并非是 exercises/ramfs_rename/src/main.rs 中的绝对路径,但 dst_path 是绝对路径。

## exercise sys_map

因为 arceos 中提供了 map_alloc 函数, 实现 mmap 的主题功能并不难, 麻烦的地方在于对各种 MmapFlags 的处理, 像 MAP_SHARED - MAP_PRIVATE, 在 arceos 中我没有找到相关的支持机制,网上也缺乏对这类 flags 如何处理的介绍( Linux 源码中的 mmap 实现是一个很复杂的系统,涉及了 arceos 没有实现的功能) 。最终,在与曾经参加过训练营的同学交流后,以及通过 Copilot 梳理 sys_mmap 的调用位置,我只添加了对 MAP_FIXED 和 MAP_ANONYMOUS 的处理以通过测试。

## exercise simple_hv

这一个练习很简单,但刚开始因为工具版本的问题被误导了: 我用的 QEMU 版本为 10.0.3,在这个版本的 QEMU 上运行 simple_hv 会产生 InstructionPageFault 异常, 因此我刚开始把目标放在解决该异常上,但查阅资料以后发现这个错误是由于访问无 excute 权限( X flag )或者未映射 PTE 导致的,我完全不知道该怎么解决( PPT 就没提及这个 ),后面和同学交流了一下才确定应该是由于 QEMU 版本问题导致的。