2024 春夏季开源操作系统训练营 日记

2024 春夏季 操作系统训练营正在进行中:4/7-6/30。

注意:本文所有观点仅为个人想法,不具有任何法律效益。

相关资料:

这几天主要就是在写 rustlings。完成到 102/110。

我越学越觉得 Rust 的很多特性其实是为了给他严格的所有权机制打补丁。最明显的就是生命周期了,还有诸如 unsafe 等。刚好最近同时也在一家公司实习做操作系统内核开发,正在使用 C 语言,因此对这两门语言的风格深有所感:

  • C 的原则就是「完全相信使用者」,因此你可以用 C 实现几乎所有操作,非常自由。但是为了安全,必须人为设计一些规范来进行约束。
  • Rust 的原则则是「完全不相信使用者」,所以你会发现 Rust 的很多语法都是为了约束程序员,强迫程序员写出安全的代码。但是,有些时候编译器还是不够聪明,或者说是无法进行判断,因此必须开点绿灯——unsafe

在 Rust 身上可以找到很多为了弥补所有权机制而设计的语法,因此在学习的时候才会觉得 Rust 的语法很复杂。不过这种「语言规定好的规范」对于多人之间的项目合作,特别是开源来说,就是一种优势了。相比于 C 语言项目之间可能存在代码风格相差巨大的情况,Rust 写出来的代码基本上不会有太大的风格差异,这样在参考别人的代码,以及贡献代码的时候就会更为轻松。

完成:

  • 完成 rustlings。

问题:

  • #[derive]#[link] 还不太熟悉作用与用法。

笔记:

  • 101-102 中的 NonNull() 是一个裸指针类型,但是实际使用的时候需要用 .as_ptr() 来获取成为真正的裸指针,并且需要在 unsafe {} 中操作。
  • NonNull().as_ptr().as_ref() 的区别是:前者返回的是指针,后者返回的是引用。换句话来说,前者需要解引用才能使用,后者直接使用就好。
  • let mut b = &mut b 中,前面的 mut 代表 b 可以绑定到另一个变量上,后面的 mut 才是代表可变借用。
  • 使用借用需要用 * 来解引用,不过如果调用了方法的话,Rust 会自动解引用:(*a).fun() 可以简化为 a.fun()
  • let a = || {}; 的意思并不是计算闭包的值然后绑定给变量 a,而是将这个闭包绑定到 a,后续就可以用 a() 来调用闭包。

这两天在弄别的事情,没有进行 OS Camp 训练。

完成:

  • 准备开始学习 rCore,配置相关环境,阅读第零章。
  • 阅读第一章,并完成实验。

问题:

笔记:

  • SMP 代表一种多核内存结构架构。具有多核的操作系统在启动的时候会有一个主核 0 先启动,然后再依次启动其他的从核。每次复位或者加电后,主核总是立即启动,从核总是延时启动。

这段时间在弄别的事情,没有进行 OS Camp 训练。

完成:

  • 完成训练营 rCore 环境配置。
  • 阅读讲义 ch1-2。

笔记:

  • 操作系统用户态和内核态的切换是通过机器指令在硬件上实现的,在 RISC-V 中这个指令是 ecall。因此,当一个应用程序想要进行系统调用的时候,需要按照约定将参数放入寄存器中,然后执行 ecall 指令,这时硬件会自动保存当前 PC 寄存器的值到 CSR 中(特权级别的控制和状态寄存器,如mepcscause),然后设置异常原因寄存器,以指示发生了环境调用异常,接着跳转到预设的异常处理程序地址,这个地址在启动时由操作系统或监控程序设置在mtvec(机器模式陷阱向量基址寄存器)或stvec(监督模式陷阱向量基址寄存器)中。至于其他通用寄存器的值,则需要操作系统来进行保存和还原。

完成:

完成:

  • 阅读完 ch3。
  • 完成 lab1 实验。

这期间在做别的事情,没有进行训练营学习。

完成:

  • 完成 lab1 实验报告的撰写。
  • 开始学习 ch4。

进度:

  • 继续学习 lab 2。

笔记:

  • 内核态采用恒等映射,用户态不采用。

完成:

  • 完成 lab2 (ch4) 实验
  • 进行

笔记:

  • GDB 在实现了切换地址空间后就无法进行调试了
  • 折腾了半天终于把分页机制弄清楚了……我之前一直在想缺页会怎么办,但其实并不会发生缺页,因为我们没有实现虚拟内存!所以一旦缺页就一定是非法内存访问。
  • 恒等映射只是在内核态使用,而且就是会和用户态分配的内存发生冲突。这样就可以直接访问物理内存,从而能够在内核态对用户态的数据进行访问。而用户态的页表采用的是 Framed,所以不能访问内核态和其他用户态的内存。
  • 当我们尝试在代码中解引用的时候,就看当前 satp 是哪个地址空间,硬件就会已经对应的页表去访问物理地址。

进度:

  • 完成 lab3 实验。

问题:

  • 当 git checkout 到任意一个之前的提交后,make run 无法正常编译。

    os 目录下的 Makefile 文件中的第 26 行:

    1
    
    CHAPTER ?= $(shell git rev-parse --abbrev-ref HEAD | sed -E 's/ch([0-9])/\1/')
    

    这里会将目前 HEAD 所指向的节点的名字用正则表达式取出目前所在的 ch,然后在第 50 行传入 user 目录的 make run 来编译对应 ch 的应用程序。

    如果目前 HEAD 所指向的节点不是 ch* 的话,那么这里的正则表达式就会失效,然后就会传出一个非法的参数,影响 user 目录的编译。

    • 解决方法:在编译的时候手动指定 make run CHATPER=[0-9] 就能解决。

进度:

  • 完成 lab4 实验。

没有进行操作系统相关学习。

进度:

  • 完成 lab5 实验。