0%

rcore秋季训练营总结

在 RCore 夏令营第二阶段,我收获颇丰,对 Rust 语言与操作系统有了更为深入的理解。在 Rust 语言学习方面,我全面掌握了其独特的所有权、借用和生命周期规则,这些特性构成了 Rust 保障内存安全的坚固防线。对于操作系统,我不再是浅尝辄止。从内核架构层面,清晰地理解了从启动到各个模块交互的过程,特别是在进程管理中,明白了进程的创建、销毁以及状态转换原理,以及不同调度算法对 CPU 资源分配的影响。在内存管理领域,深入研究了从物理内存分配到虚拟内存映射的机制,页表机制作为连接二者的关键,让我惊叹于内存管理的复杂性和精妙性。在实现小型系统组件的个人项目中,我将 Rust 与操作系统知识融合,经历了从设计、实现到调试的完整流程,在解决诸多难题中实现了自我提升。这一阶段的学习为我打开了新世界的大门,未来我将持续探索,把所学更好地应用于实践。

第三阶段总结报告

学习

跟着看了大课,第一周的实验题尝试解决了,到第二周的宏内核后时间紧促就先看课了。

这里我谈谈我对于课程内容的理解吧。

首先是Unikernal,直观的第一眼看的话,Unikernal像是不划分用户空间和内核空间的操作系统,
同时也没有页表机制,不开虚拟空间,内核是一次写好的,app加载是配置文件一个一个分配的。这样的内核
就像是实验室产品一样,用户都是开发者权限,它的性能也是极度的优异。不过嘛,不分权,所以安全性很容易受威胁

接下来是宏内核,宏内核是常见的平时家里用的操作系统模式,宏内核地址空间的引入好处益处在学习操作系统时是所有人必背的。
它的内存分配,进程调度,也都是耳熟能详的。

最后是这个hypervisor,我最开始学习的语言是C,后面走了C++,所以对于虚拟机的机制只是略有耳闻,这里更深入的
探讨了虚拟机是如何实现,虚拟机的实现使

思考

异构扩展化的操作系统内核是个很令人兴奋的话题,就是这个内核你不能当他是某一个具体的内核,它可以执行各种app,关于异构
在智能物联这我有个想法,就是如果说是各个物品之间的交互的话,可以用统一的协议。那如果,这些物品可以在物理上链接在一起,
那么可不可以执行一个新的效果?就是比如,全屋有一个统一集中的管家,它是有个物理实体的”大脑“的,很多家电与它是进行”硬链接“,进行更快速,更高效的交互,控制。
当然,也可以通过网络链接,不过这是提供了另外一种方式。

方向

我选择本期的方向四,基于协程异步机制的操作系统

Rust之路

与Rust的邂逅,应该是大概2020年的某个白天,在TIOBE编程语言排行榜中突然看到了一个陌生的语言Rust。它的名字引起了我的好奇心,这个语言的出现,似乎暗示着某种新趋势,毕竟在那个时候,Python、Java和C这些传统大牌仍然占据着榜单的前列。

我当时并没有立刻去深入了解它,而是简单地在网上搜了一些资料。初步了解之后,我发现Rust似乎是一门致力于解决内存安全和并发问题的系统级语言,它通过所有权、借用和生命周期的概念,确保了内存的管理比C/C++更加安全,却又不牺牲性能。这个点吸引了我,因为作为一名从事系统开发的工程师,我深知内存安全问题的复杂性和严重性。

随着时间的推移,我开始在工作中接触到更多关于Rust的讨论,特别是在一些性能优化和系统底层开发的项目中。于是,我决定亲自试试Rust,看看它是否真如资料中所说的那样,能在保持高性能的同时,还能提供更高的安全性。

刚开始学习Rust时,我对它的独特设计感到既惊讶又困惑。尤其是Rust的所有权模型,它要求程序员明确控制内存的使用,这与我之前接触过的语言截然不同。比如,在Rust中,每个值都有一个所有者,并且只能有一个所有者,这样就避免了传统语言中的内存泄漏和悬垂指针等问题。起初我觉得这些概念过于复杂。每当编译器抛出错误,我常常需要花费大量时间去解读错误信息,理解这些错误背后的内存模型。

后面学习了几个rust视频,前后入门了好多回,才算弄懂了rust中一些基本的概念。学习过的视频里边最值得学习的当属Rust编程语言入门教程,这个视频的作者是微软的MVP开发者,讲解rust思路非常清晰,从不拖泥带水,并且视频做了后期处理,应该跳过的地方做了加速处理。

2024年初,通过rust中文社区微信公众号得知了opencamp训练营,由于所从事的行业跟操作系统打交道比较多,自己有比较喜欢rust,于是参加了cicv第一届中期训练营,这次也是抱着试试的心态,因为之前的初级训练营都没有参加,自从这次训练,通过rustlings的练习及课程中老师们对rust的讲解,以及最后的实践项目,rust进步了很多。

这次秋冬季开源操作系统训练营,很早之前就预览了往期的一些课程,看了往期的课程更是喜欢不已,很早就盯着开课的日程,终于在开课的第一时间就参加报名了,课上除了巩固了rust的很多基本知识,也学习到了一些新的有趣的特性,随着学习的不断进行突然又觉得自己只是学了个皮毛,rust还有大量的内容需要去摸索去学习。

总结起来,我与Rust的邂逅虽充满曲折,但最终成就了我作为开发者的一次重要转变。Rust教会了我如何更加精细地思考代码的内存管理和并发处理,如何通过语言本身的设计,去实现更高效、更安全的系统编程。在这段学习旅程中,我深深感受到它带给我的不仅是技术上的提升,更是思维方式的转变。

Rust学习资源

crates.io
docs
Rust Language Cheat Sheet
rust std
The Rust Programming Language
Rust 程序设计语言 简体中文版
Rust By Example
通过例子学 Rust
exercisms.io 快速练习
Learn Rust With Entirely Too Many Linked Lists
leetcode for rust
Command line utilities
Rust标准库分析 inside-rust-std-library
Rust Playground
rustexplorer
Rust编程语言入门教程

Rust个人小项目

基于wasm的四六级英语学习项目
vnc的rust接口封装项目
kubevirt客户端工具
虚拟机加压工具

第一阶段

这一阶段没啥好说的,之前已经参加过好几次训练营了,rustlings 也不知道是三刷还是四刷来着,总之还是很顺利的

第二阶段

这次第二阶段相较上一次进步就很大了(上次只做了lab1),总体而言感觉收获还是很大的

对我而言,最难的是lab2和lab4,光看文档是真不懂,还是得 RFSC

在理解页表分配的时候,一定要根据link.ld画内存图帮助理解,不然真的会绕晕,之前在学习操作系统的时候只知道有这么个机制,真到实现起来的时候才发现这么复杂,有些认为想当然的功能都要通过很复杂的调度

lab4代码很多,但是写起来是有技巧的,当我看到文档上说到“松耦合”的时候,就提醒了我一点:既然已经做好了解耦的工作,那也就意味着我在编写内核的时候其实是应该不需要太关心文件系统的具体实现的,只要调用固定的几个API应该就能完成任务。

果然,在逐个观察几个相关的系统调用的实现之后,我找到了几个关键的API,还算轻松地完成了任务

写lab5的时候有点被群里的人带偏了,还以为要实现银行家算法,清醒过来之后才发现是死锁检测

开源操作系统训练营第二阶段总结

学习契机

之前有断断续续看过一些课程,没有加入到学习训练营中,自己一个人没有啥动力。这次通过其他其群的信息,加入训练营和大家一起开始学习,一起探讨,最终完成了所有课程的学习,并完成了题目练习。

学习内容

  • 了解操作系统的基本概念和发展历史
  • 了解操作系统的基本原理和设计思想
  • 学习了操作系统的一些基本概念,如文件系统、进程、线程、调度、死锁、互斥、信号量、管道等。

学习心得

和大家一起学习,更加容易坚持到最后。学习中遇到的问题,也可以及时和群友讨论。因为需要完成题目拿分数,有时候会功利性比较强,以完成测试为目的,忽略掉一些知识点。最后学完之后可能容易忘记,可能需要多多复习。

开源操作系统训练营第一阶段总结

学习

  • 学习了rustlings的课程,并完成了所有练习。

心得

  • 学习之前主要还是需要看完官网推荐的书籍,然后再去学习和练习。
  • 练习过程中,可以边做边学,遇到问题可以及时查阅文档和群友进行讨论,避免陷入牛角尖。
  • 借助ai的帮助,可以更快的学习和掌握知识。

收获

  • 通过rustlings的练习,对rust的熟悉程度有了更深入的了解。
  • 了解使用rust来实现一些数据结构和算法。

第二阶段总结

这个阶段主要是要完成几个实验,借助几个实验理解一个具有进程/线程管理、内存管理、文件系统、进程间通信和提供了一定同步机制的内核是如何构成并运作起来的。

比较深刻的有这么几个知识点:

  • 链接脚本与全局符号的使用
  • Rust的汇编嵌入
  • 第四章中,在使用分离内核空间的时候。通过设计跳板页来解决切换页表后指令执行的问题。跳板页
  • 第六章了解了文件系统,了解了块设备的概念,对文件系统的各个抽象层有了一定的了解。
  • 第七、八章了解了操作系统是如何为应用提供同步原语的

跳板

由于我们的内核使用了分离内核空间的设置,所以在Trap的时候需要切换页表。但在切换页表之后,pc寄存器还是忠实的在其原来的位置自加到下一条指令,如果内核内存空间程序内存空间对这段代码的映射不是在同一个位置的话,则会表现出来程序跳转到了别的地方执行的效果。因此我们设计了一个跳板页,在虚存中映射到所有内存空间的最高页,确保在切换之后,也能正确运行下一条指令。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# trap.S
...
.section .text.trampoline
.globl __alltraps
.globl __restore
.align 2
__alltraps:
csrrw sp, sscratch, sp
...

# linker.ld
...
stext = .;
.text : {
*(.text.entry)
. = ALIGN(4K);
strampoline = .;
*(.text.trampoline);
. = ALIGN(4K);
*(.text .text.*)
}
...

在上面的汇编可以看到,我们给trap.S分配到了.text.trampoline段,并在链接脚本中定义了一个strampline符号来标记他的位置,这样我们可以在Rust中找到这个跳板页,映射到我们期望的位置。

但将跳板也映射到别的地方带来了新的问题,原来__alltraps中最后跳转到trap_handler使用的是call trap_handler。我们可以通过obj-dump看看编译得到的指令。

1
2
3
4
5
6
7
8
9
10
# obj-dump -Dx ...

...
80201056: 73 90 02 18 csrw satp, t0
8020105a: 73 00 00 12 sfence.vma
8020105e: 97 80 00 00 auipc ra, 0x8
80201062: e7 80 e0 0b jalr 0xbe(ra) <trap_handler> # pc+0x80be
...
000000008020911c g F .text 00000000000003b2 trap_handler
...

可以看到,这里用的是pc相对寻址,也就是基于当前指令的偏移找到trap_handler所在的位置。但是现在__alltraps已经被我们映射到内存的最高页去了,也就是说我们实际运行代码的时候是在下面这一段内存中。

1
2
3
4
5
6
7
8
9
# gdb
>>> x /20i $pc-10
0xfffffffffffff054: ld sp,280(sp)
0xfffffffffffff056: csrw satp,t0
0xfffffffffffff05a: sfence.vma
=> 0xfffffffffffff05e: jr t1

>>> p /x $t1
$9 = 0x8020911c

很明显如果这里跳转到$pc+offset$的话,并不是跳到位于正常代码段的trap_handler。所以我们要将这里换成寄存器跳转,将trap_handler的地址放到寄存器t1中,这样才能顺利地调用到trap_handler

第一阶段总结

原版rustlings曾经做过,但是这次添加了一些题目,不过也曾经在exercism.org上接触过相似的
通过这110道题,完整的复习了一遍Rust的相关基础知识,特别是最后的几道很有Rust特色的数据结构题

内容

  1. 特权级切换
  2. 虚拟CPU(进程调度)
  3. 虚拟地址
  4. 文件系统
  5. 进程间通信
  6. 多线程
  7. 资源共享

    遇到的困难

  8. rCore抽象层次多,第一次编写系统调用时,缝合代码逻辑困难
  9. 程序之间进行切换的上下文资源维护
  10. 虚拟硬件资源的抽象
  11. 文件系统的内存映射
  12. 银行家算法设计
  13. 系统调试

    收获

    阶段二的完成让我对操作系统的运行有了全局的认识。在紧张的时间内完成了阶段二的任务,真正的帮助我了解了系统级编程。在以后的学习生活中,更容易占在全局的角度看待问题。
    我特别喜欢的一句话是“没有什么问题是加一层抽象层解决不了的”。