0%

2024春夏季开源操作系统训练营第二阶段总结报告-郑昱可

本阶段的收获

经过半月多的赶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内部,进程可以拥有多个线程,线程之间共享内存空间。

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