0%

本阶段的收获

经过半月多的赶ddl(,加上老师群友们的无私帮助,我成功的完成了第二阶段的任务。

不仅对Rust的掌握程度更深了,并且对操作系统中很多概念有了实际上的理解。

包括且不限于:

  • 特权态的切换
  • 地址表,页表的管理
  • 进程和线程的区别
  • 执行流切换和恢复
  • 线程调度

同时,这些知识很大程度上帮助我消除了对裸机编程的恐惧。对计算机底层的运行方式有了清楚的认知。

一个尝试-Rust in ch32v003

在前几天结束第二阶段的作业后,我是打算了摸几天鱼,正好看到桌边吃灰的ch32v003单片机。

ch32v003是一块携带了riscv指令集芯片的单片机,我手头上这块,实现了riscv标准中的mai,以及f。
美中不足的是,它只有S态和M态,并没有实现U态。

于是我萌生出想法——为什么不试试将Rust代码运行在这上面呢。

ch32-hal

Rust在嵌入式方面的库,在2024年的今天已经较为完善了。在createio中查找一番后,我看到了ch32-hal,以及与其配套的qingke-rt

ch32-hal将ch32系列的单片机的外设进行了rust封装,使得在代码中能方便的进行调用和更改

如修改SYSTICK的ctlr位,只需要以下代码

1
SYSTICK.ctlr().modify(|w| w.set_ste(false));

qingke-rt则包含了运行时相关的内容,可以在main函数前添加#[qingke_rt::entry],使得该函数称为编译后程序的入口函数

并且qingke-rt也可以通过类似的方法定义中断处理函数。类似的工作,我们在rcore实验中是通过内联汇编手动修改相关寄存器实现的。

代码

以下附上一个点灯代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#[qingke_rt::entry]
fn main() -> ! {
let mut config = hal::Config::default();
config.rcc = hal::rcc::Config::SYSCLK_FREQ_48MHZ_HSE;
let p = hal::init(config);

let mut delay = Delay;

let mut led = Output::new(p.PC2, Level::Low, Default::default());
loop {
led.toggle();

delay.delay_ms(500);
let val = hal::pac::SYSTICK.cnt().read();
}
}

理论和实践

之前在学习体系结构的知识时,书本上只有几张图来描述代码执行流的切换,于我而言并不直观。甚至很长一段时间我是当做文科的内容来学的。

经过了本次实验后,令我印象最深的是__switch函数,通过寄存器内容的切换,便可切换到另一个执行流上。

而执行流,在某一时刻无非是:

  • pc指针的位置
  • 栈指针的位置
  • 若干存储在当前寄存器中的变量

而对执行流,进一步抽象成包含若干线程的进程。

对若干的进程进行管理,并为进程提供服务,就是操作系统。

文件系统

在此之前,我对ntfs之类的文件系统没有一点了解。在这次实验中,了解了一个简单文件系统的实现,并且通过easyfs实现了一些功能。

同时,简单了解到了对于硬件驱动的编写,以及将不同的硬件驱动,抽象成相同的软件内模型。在软件内进行多层抽象,每层抽象负责简单的几件事情。

这样能够方便错误判断,多层抽象的思想我最先从网络原理中了解。easyfs的实现方式,进一步的说明多层抽象在计算机软件编写中,可以称得上是最佳实践了。

进程&线程

不去亲自阅读操作系统源码,是很难对进程和线程有明确的理解的。

甚至很长一段时间,我对进程和线程并没有区分。而在OS内部,进程可以拥有多个线程,线程之间共享内存空间。

对于这点的了解,不仅是系统编程领域,对我普通的软件编程也大有裨益。

第1~2章

总的来说这两张花的时间是比较久的,因为完全没有学过操作系统,对概念上的理解用了一些时间,真的跟着代码学习的时候,不知道这些代码之间的联系,不知道用户程序和操作系统是怎么联系起来的。

因此总结了一个大概流程:

build.py编译user里面的用户应用程序:

img

启动qemu和rustsbi,编译os

img

执行build.rs,将bin文件插入到link_app.S,生成link_app.S

链接

main.rs运行batch.rs,开始批处理

batch.rs首先初始化一个实例:APP_MANAGER: UPSafeCell

从link_app.S里面找到_num_app符号,找到每个app的地址存进app_start数组,然后将其打印出来

然后依次执行应用程序,其中应用程序出现错误或者开始下一个应用程序时,需要有用户态到内核态的切换。需要用到Trap.S

img

开始批处理

img

保存Trap上下文,之后进入trap_handler,正常情况下会返回并继续执行下一个应用程序

img

这个函数不会返回,会一直将加载应用程序并把当前的应用程序的上下文压入内核栈,sret后就会自动执行下一个应用程序,直到完成

第3章

主要是学习分时操作系统,概念上还是比较好理解的

第4章

学习了地址空间,一开始对于这几个概念比较混淆:

  • 虚拟地址
  • 虚拟页号
  • 物理地址
  • 物理页号
  • 地址空间

后来根据这个图搞懂了

img

  • 虚拟地址指的是在地址空间里面,数据的地址

  • 虚拟页号指的是虚拟地址字段里面的一个字段,这个字段可以在物理页表上查到一个物理页号,最终通过多级页表,查找到这个虚拟地址对应的物理地址,从而真正在主存读写数据

  • 每个应用的地址空间可以被分成若干个(虚拟) 页面 (Page) ,而可用的物理内存也同样可以被分成若干个(物理) 页帧 (Frame) ,虚拟页面和物理页帧的大小相同

  • 地址空间:一系列有关联的逻辑段:

    地址空间是一系列有关联的逻辑段,这种关联一般是指这些逻辑段属于一个运行的程序(目前把一个运行的程序称为任务,后续会称为进程)。 用来表明正在运行的应用所在执行环境中的可访问内存空间,在这个内存空间中,包含了一系列的不一定连续的逻辑段。 这样我们就有任务的地址空间、内核的地址空间等说法了

    也就是说,地址空间的逻辑段不一定连续,这就对应了编程题,如果要写的内容太大导致分页,应该直接将内容也分页塞入到其物理地址里面去

第5章

需要记的就是进程是怎么调度的,switch函数的作用

就是最初,先创建一个idle进程,然后将switch的参数设置为idle进程和第一个程序,使得第一个程序可以执行

然后就调用 task 子模块提供的 suspend_current_and_run_next 函数可以暂停当前任务,并切换到下一个任务

这一章完成后,一个应用程序可以主动交出CPU的使用权,这样一来,它需要等待某个资源的时候,CPU就可以去执行其他程序了

第6章

这一章的概念也看得我很晕

主要是:

  • 索引节点和文件有什么关系?
  • 目录和索引节点又有什么关系?
  • 一级索引存在哪里?二级索引指向哪里?
  • inode和DiskInode是如何映射起来的?

因此画了这个示意图:

img

对于lab,感觉比较难的是理解几个inode之间的关系,比如通过文件名如何查找其对应的inode_id?

第7~8章

终于要结束了

第8章的概念比较好理解,对我来说比较难的是理解lab里面死锁检测算法的含义

一开始写的时候只考虑了能否解开一个锁,总感觉哪里不对。后来发现,其实要考虑能否解开所有的锁,因为解锁的顺序是要考虑的,如果只考虑能否解开一个锁,那么这个解锁顺序可能无法实现。

第二次参加训练营了,之前已经写过一段时间的Rust了,题目和记忆中差不太多很快就做完了。
遗憾是每次参加训练营的时候,学校的安排都很紧,希望这次有时间能进三阶段吧

第一阶段总结

很早听闻Rust是一个“内存安全”的语言,出于好奇,我从去年就开始接触Rust,Rustlings也是我最开始学习Rust使用过的教程之一。因为之前写过一遍,这次重新再写速度快很多。然而完成的过程中,还是发现有些语法不常用到,很容易遗忘。比如结构体初始化可以使用已有变量的内容,这个地方我写Rust的时候几乎没有用到。

相比于之前的rustlings,新的rustlings增加了算法这一个章节。通过完成基本的数据结构,我们可以比较好的了解rust在写底层的数据结构的时候会遇到的困难,特别是rust在操作链表时的“不自由”。由于所有权的问题,链表等在C和C++常用的指针修改操作会非常的痛苦。小的技巧是我们可以用Option来类似于进行指针的操作,使用Option实现方法take和insert来进行内部修改。

Rust的包管理器Cargo相比于C++的Cmake对用户很友好,虽然Rust现阶段的工具库并没有像Java一样丰富,但一般Rust的库都会有比较好的文档说明,所以一般库的质量还是有保障的。

总之,我觉得Rust是一个非常有前景的语言。

二阶段学习收获

做了二阶段,又受到了rust的拷打。。。

因为本身我是做过ucore的,且那个版本的ucore比训练营的要难。明显能看出来训练营的简化了rcore的部分练习题,但是依然是一个比较大的工作量。

总的来说,训练营的rcore版本并不是很难,对我自身而言,更难的部分在于rust的语言本身。

因为rust本身的检查,导致很多时候往往不能拿到正确的类型,比如操作inner等等。

且本身的要求的互斥访问也很多时候卡住了我,编译通过但是运行时出现了问题,,,总结的教训就是不要在调用里使用调用。。。大概率会出很大的问题。

也是因为此,rust本身的要求导致我必须再次详细的读框架源码,选择合适的构思方式来完成任务,附加品就是能够更好的学习源码。。。

实验情况

做这个实验,一共用了大概有一周吧,完整的做完了5个实验,期间加上上课、写作业等各种事情,总体来说,个人感觉最难的地方是内存和文件系统。

因为这两个实验跟框架很大的关系,需要你去大改框架,而这往往会引起rust的编译错误。。。淦

实验的具体总结和过程在此就不多说了,具体见下面的每天日记:

rCore-OS-2024Summer

本来打算挂到我的博客的,但是因为是随笔性质的,写的有点乱,就懒的整理了,挂仓库吧。。。

最后

就写这么多吧,更多的是碎碎念,实验过程都放仓库里了。

前沿

一直对操作系统挺感兴趣的,最初是没事看南大jyy的网课,但是因为没有公开测试,就一直当作科普内容来看了,并没有认真做实验,加入了一个找系统相关实习的qq群,看到别人发了这个操作系统的训练营,大概了解了一下就报名参加了,参加的比较晚

学习过程

在最初学习rust的过程感觉挺简单的,基本上是安装rustling的顺序做,然后每一个内容的看一下rust语言圣经那本书,感觉讲的挺清晰的,在前期题目做的很快。后来因为要毕业了忙着赶毕设和毕业论文就暂停了差不多两周左右。再回来继续做rustling发现很多语法和特性都忘得差不多了,花了2-3天的时间,把rust语言圣经很多内容都看了一遍,看的都差不多了就又继续写rustling了。总体感觉rust是一个非常复杂的语言,里面的很多语法特性和独特的所有权,trait,多种类型的智能指针等,都是我之前所学的语言所没有了解过的,虽然题目都做完了,但是感觉自己的rust了解已经不是很熟悉和透彻,希望在第二阶段的项目开发中能够提高我对rust的运用吧。

感想与规划

自己想学Rust很久了,但一直没有行动起来。然后自己最近也在为1年之后找工作有点焦虑,想着找一些开源项目做一做,自己也对os比较感兴趣,然后搜了一下os开源训练,接着就了解到了这个开源操作系统训练营。

大概花了5 6天的时间把《rust权威指南》看完了,把rustlings刷完了,总体来说难度不高,主要涉及的是rust的语法,没有很深入的地方。最后10个rust写算法的练习算是对所学语法的巩固,这里面还是踩了不少所有权、生命周期的坑。题目本身不难,但要一次通过还是比较考验对rust的掌握程度的。我个人总结的rust比较核心、困难的知识点如下:

  • 所有权
  • 生命周期
  • 借用,共享借用与可变借用
  • 智能指针:Box, Rc, Arc, RefCell
  • trait与泛型
  • unsafe rust

接下来希望能继续巩固rust,用rust写一些项目。

  • 读《Programming Rust》这本书,加深对Rust的理解
  • 读《Effective Rust》,学会Rust的最佳实践
  • 看rust死灵书的课
  • 用Rust完成本次开源操作系统训练营,争取能达到项目实习的水平
  • 用Rust写一个toy编译器
  • 用Rust写一个toy数据库

2024开源操作系统训练营第一阶段总结-高泽文

本文是对OS训练营第一阶段的总结

1.
rust非常的严谨(通俗来说就是要求特别多)
对变量的限制更多了相比于cpp等语言 对于我写习惯cpp之后,太不适应了一开始 ,但是也一定会有好处,
代码的安全性是它最重要的一点,而且rust编译器的提示也非常的方便 减少运行的错误。
2.安全性完全吸引我了,独有的所有权系统和生命周期规则解决了cpp的空指针 null 内存泄漏等 其次还有多线程的安全保证 (鉴于自身水平所以对于多线程安全摘自文心一言的一段:Rust通过其强大的并发原语,如Arc、Mutex和Atomic类型等,为多线程编程提供了安全的支持。这些原语使得开发者能够在不使用垃圾回收的情况下,安全地共享和管理内存。同时,Rust的所有权系统也确保了同一时间只有一个线程能够访问某个数据,从而避免了竞态条件和其他并发问题。)
3.还有rust的社区是真的友好 我第一次了解到还可以在社区学习语言,圣经就是非常好的一个教程

###rust一阶段学习总结
rust和之前学过的java,python,c有很多的不同。尤其是rust的所有权的方面,让人又爱又恨。
写完了rustlings的110道题目让我对rust有了初步的认识,还需在后面的阶段中深入学习以及巩固。
一阶段存在的问题是效率还可以提升,花费了出乎意料的较长时间,后阶段要更加高效解决问题。
较好的方面是持之以恒,在繁忙的学业中抽出时间,是很困难也是很需要毅力的,希望自己后面可以保持。