第三阶段和第二阶段相比明显更加基础,虽然有一些第二阶段涉及过的内容,例如任务切换,地址空间等等,但是第三阶段重点在于ArceOS和组件化操作系统,强调了如何从裸机(或者qemu)上通过各层模块的调用实现一个完整的操作系统。
Unikernel
第一周的课程围绕着unikernel展开,讲解了使用各个组件来实现一个unikernel。包括内存分配,地址空间,任务与运行队列,调度,块设备驱动和文件系统。
以实验1为例,要求修改println的输出颜色。
不难发现println!基于ulib调用arceos_api,实现输出流调用抽象层axhal中的console::write_bytes进行不同platform的putchar()来操作sbi。所以在ulib处或者axhal处使用ANSI escape codes都可以起到目标的效果,并且在ulib处只作用于println!,而在axhal处作用于启动后的所有输出。
tour2同理,找到调用的modules/axalloc模块,发现其cargo.toml默认为未实现的lab,进行修改即可。
就这样,我们通过config,可以在rust便捷构建unikernel组件。接着的课程继续处理调度,总线,文件系统等来构建一个完整的unikernel。
Monolithic
接下来的课程带领我们从unikernel跨到宏内核,主要任务在于用户空间和内核空间的切换。
从Unikernel基础到目标最小化宏内核需要完成的增量工作:
- 用户地址空间的创建和区域映射
- 在异常中断响应的基础上增加系统调用
- 复用Unikernel原来的调度机制,针对宏内核扩展Task属性
- 在内核与用户两个特权级之间的切换机制
我了解了riscv下进入用户态的伪造现场机制,剩下的内容就是处理好用户态的地址空间,实现musl工具链。
这部分很有意思的内容有一个关于异构内核的讨论,也就是说实现异构内核的Task结构体来记录任务信息,但是在异构核上不同的task需要记录的信息是不一样的。
如果在task结构体上直接通过编译选项控制的话,不利于扩展性,使用基础属性和额外属性的关联索引则需要查找开销,所以引入类似TLS的指针扩展机制是一个折中的方案。
Hypervisor
第三周的内容就是关于RISCV的虚拟化了,虽然在之前了解过虚拟化的大致原理,但是深入了解RISCV硬件支持的hs和vs寄存器组和sv39的页表扩展,仍然感到这样的设计之精妙。
课程详细讲解了hyperv上抽象的VCPU结构体和如何实现VM_entry,VM_exit,接下来再介绍包括透传,中断等其他事项的处理。
End
受限于课业忙碌,笔者并没有对挑战任务做出贡献,也缺少对arceos的深入了解,但是课程提纲挈领的讲解令我收获良多。