实验八:扩展实验¶
海阔凭鱼跃,天高任鸟飞。
——《古今贤文》
实验任务与要求¶
首先,祝贺你已经顺利完成了前面的实验,你已经拥有了一个基本的操作系统内核,它可以在 QEMU 中运行,并且可以通过串口输出进行交互。
它有自己的进程管理机制,可以从磁盘中加载用户程序进行执行;它有自己的同步互斥机制,可以让多个线程安全地访问共享资源;它有自己的内存管理机制,可以在内核态和用户态之间进行内存的分配和释放。
在这个实验中,你需要在这个基础上,自主实现一些更加有趣的功能,例如图形输出、文件系统、内存分配、块设备缓存层等。
请从下列任务中,选择一到两个目标进行实现:
VGA 显示输出¶
串口输出只是最基本的交互方式,尝试在 bootloader 中,利用 get_handle_for_protocol::<GraphicsOutput>
获取到 VGA 显示的模式、分辨率、缓冲区地址等信息。
之后通过利用 embedded-graphics
等库,实现一个简单的图形输出驱动,赋予操作系统绘制图形的能力,之后实现一个简单的 Shell 显示,并激活键盘输入的驱动,通过和串口启动共享缓冲区的方式,响应键盘输入。
实现目标¶
- 在 bootloader 中,获取图形输出的相关信息,并传递给内核。
- 实现一个简单的图形输出驱动,支持基本的 VGA 图形绘制操作。
- 利用
embedded-graphics
实现字符渲染。 - 为 VGA 显示实现一个 Shell 输出,使其能够输出字符、清屏等,并将其对接到合适的日志输出。
加分项¶
- 利用键盘输入中断,为 QEMU 的 GUI 界面实现输入输出。
- 尝试将 Shell 部分限制在屏幕的下半部分,并在上半部分实现一些图像的绘制。作为一个例子,你可以利用
sleep
等方式,实现一个不断绘制转动的钟表的进程,并让它作为一个后台进程运行。
可读写的临时文件系统¶
根据现有的其他 OS 实验中的文件系统设计、或参考现有的文件系统设计,结合你学过的算法、组织数据的方式,实现一个简单的文件系统的驱动。
可以是目录结构文件系统(例如参考 FAT32),可以是日志文件系统(例如参考 ext4、NTFS)。实现之后利用帧分配器在操作系统初始化分配一段内存空间,将其作为块设备,使用你的文件系统对其进行格式化、挂载、读写等操作。为了更好的实现你可能需要适当增大启动 OS 的内存量。
实现目标¶
- 将启动目录挂载至
/boot
目录下。 - 将临时文件系统挂载至
/tmp
目录下。 - 创建
/tmp/mydir
目录。 - 创建
/tmp/mydir/hello.txt
文件。 - 向
/tmp/mydir/hello.txt
文件写入一段字符序列,包含你的学号。 - 读取
/tmp/mydir/hello.txt
文件,将其中的字符序列打印到屏幕上。
加分项¶
- 尝试实现文件系统的硬链接,并测试读写操作。
- 修改 QEMU 参数,挂载一块虚拟磁盘,尝试实现文件的持久化。
内存管理算法¶
在上次实验实现了堆内存的分配和释放后,用户态有了自己的能力去管理自己的页面,但是其实际的动态内存分配还是依赖于内核提供的服务。
在这个实验目标中,你可以尝试实现一些内存管理算法,例如 Buddy 算法、Slab 算法等,将其作为内存分配器,为用户态提供更加灵活的内存分配服务。
不过,在这一目标中,你大概率需要一个链表,你可以找一些现成的实现,或者选择完全的自己实现。
实现目标¶
- 在
pkg
下添加一个独立的新package
,用于实现能够测试的内存分配器。 - 参考
storage
包进行测试配置,并配置好no_std
等属性。 - 在其中实现你的内存管理算法,参考
LockedHeap
的内存初始化方式,管理一段内存。 - 在
lib
中为你的内存分配器声明一个feature
,并将它声明为#[global_allocator]
。 - 编写测试程序,并测试你的内存分配器能否正确分配内存。
加分项¶
- 成功利用
brk
和你自己实现的内存分配器,实现用户态的内存管理。 - 尝试让你的内存分配器支持调用
brk
进行扩容。
将你的内存分配器作为 static
变量在线程间共享使用有助于避免线程导致的内存错误。
块设备的缓存层¶
在 storage
包中,基于目前已有的实现,实现一个块设备的缓存层。
这里给出一个缓存设备结构体的设计参考:
1 2 3 4 5 6 7 8 |
|
其中,CacheManager
trait 定义缓存层的缓存管理器,在预期的实现中,你并不需要在这里实现具体的缓存算法和数据结构,而将其留在 kernel
中实现。
实现目标¶
- 对设备缓存层、缓存管理器、缓存块进行抽象,并进行泛型设计。
- 缓存管理器提供缓存块的获取、存储能力。
- 缓存块实现脏数据标记、缓存块的读写,并为自身实现
Drop
时的自动写回。 - 为设备缓存层实现
BlockDevice<B>
trait。 - 在内核中定义实际的缓存结构体,为它实现缓存管理器的相关功能。
- 在最后的实现中,你应当能够将缓存层作为
Fat16
的inner
。
加分项¶
- 向操作系统暴露缓存的使用情况,并在系统状态中进行展示。
- 验证缓存是否能带来一定的性能提升,设计相关测试并记录输出。
多核进程调度¶
在之前的实现中,进程只会在同一个核心上被调度执行,而在实际的多核系统中,多个核心可以并行地执行多个进程。
在这个目标中,你需要实现一个简单的多核调度器,使得内核能够在多个核心上调度多个进程。
实现不要求性能,结合能够找到的资料和相关理论知识,能够验证多核运行就是成功。
实现目标¶
- 修改
apic
初始化部分,利用cpuid
使得它能够在多核系统中正确初始化多个 LAPIC。 - 初始化部分建议查阅文档,并参考其他现有的实现。
- 尝试实现操作系统的多核调度,并进行适当的日志显示。
- 尝试在用户态验证,并输出运行的核心序号、进程 ID 等。
加分项¶
- 尝试实现进程亲和性,使得进程能够在特定的核心上运行。
- 实现多核多队列模型,或尝试实现任一负载均衡算法(二选一)。