Forked from Maturin / OSKernel2022-Maturin
80 commits behind the upstream repository.

Maturin

一个内核。

Doc

初赛文档见这里

Usage

$ rustup component add rust-src llvm-tools-preview
$ rustup target add riscv64imac-unknown-none-elf
$ cd kernel
$ make testcases-img
$ make run

注意qemu版本至少应为6.0.05.0版本的qemu自带的opensbi的在启动时的行为不一样。

Directory tree

/user

用于测试的用户程序。部分参考了 https://github.com/rcore-os/rCore

/dependencies

直接抓下来的依赖库,为了规避评测机本地没有又连不上网的问题。

注意并不是所有依赖库都在这个目录下。经过大幅度修改、只适用于这个OS的库没有放在里面。

/dependencies/bitmap-allocator

一个分配器,用于页帧和pid分配。来自 https://github.com/rcore-os/bitmap-allocator

/dependencies/kernel-sync

依赖库,提供在使用时关中断的 Mutex ,来自方便在内核常开中断

/dependencies/core2

提供 no_std 下原来 std::io 类型的相关 Trait 实现,来自 "https://github.com/bbqsrc/core2"

/dependencies/easy-fs

之前使用的文件系统,来自 rCore,是https://github.com/rcore-os/rCore-Tutorial-v3 的一部分。

目前已弃用。

/dependencies/easy-fs-fuse

配合 easy-fs 导入用户程序。来自 rCore,是https://github.com/rcore-os/rCore-Tutorial-v3 的一部分。

目前已弃用。

/fscommon

文件系统在内存中的 buffer 层抽象。

本来应该是 rust-fatfs 的依赖库,来自 https://github.com/rafalh/rust-fscommon,但它所依赖的 core_io 库限定死了 rustc 版本,而且已经没有再更新了,导致新版的编译库无法在 no_std 下 build 这个库。在 这个issue 里能看到同样有其他人遇到了从 rust-fatfs 到这个 core_io 的依赖库问题。 解决方案是换掉 core_io,改为 core2

更换依赖库后,因为这两个库还是有一些接口上的不同,所以 Cargo.tom;/dependencies 和代码也需要修改。改后的项目已经和原项目不同了,因此你可以看到在 kernel rust-fatfs 的依赖中,fscommon 都使用相对路径。但是在 fs-init 中直接使用的是原版的 fscommon,因为它需要在 std 环境下运行,而修改后只支持 no_std 了。

fscommon 原项目采用 MIT License,修改后的项目也不变,所以可以在 Cargo.toml 中找到原作者和项目的信息。不过因为忘记在改这个模块的代码前 commit 一次,所以可能不太方便比较修改了哪些内容。

所以 core_iocore2 的作用是

引入它们都是为了提供在 no_std 环境下类似 std::io::{Read, Write, Seek} 的接口。

rust-fatfs 需要针对 fscommon::BufStream 进行读写,它相当于一种缓存,本体在内存中,但会在需要的时候读写"文件",且在 Drop 时也会自动写回"文件"。上文的文件在 std 环境下可以是 std::fs::File,但在 no_std 环境下,如这个OS,可以是一个块设备。 为了对不同的"文件"都能实现缓存,fscommon::BufStream 中对这个"文件"的要求就是实现 std::io::{Read, Write, Seek}。当然,no_std 环境下需要找一个类似的接口,如原项目的 core_io 和现在的 core2

内核为什么要关心这个接口

因为内核需要把 MMIO 提供的块设备接口包装成 fscommon::BufStream 所需要的实现了 Read, Write, Seek 的接口,所以内核必须先知道这三个接口来自哪里,有什么要求,才能对应实现 Trait

/rust-fatfs

一个FAT32格式的文件系统示例,来自 https://github.com/rafalh/rust-fatfs

这个文件系统本来是面向单核的,现改成了多核实现。具体来说需要 RefCell/Cell 改成 lock::Mutex、各个结构体内对文件系统本身的带生命周期的引用 &'a FileSystem 改为 Arc 等等,然后手动检查冲突和死锁。

/fs-init

手写的工具,用于将用户程序加载到文件系统。

启动的完整流程是:

  1. \kernel 下编译内核;
  2. 先在 \usermake ,生成用户程序;
  3. 然后在 \fs-initmake ,生成文件系统镜像;
  4. 最后在 \kernel 下启动 qemu,加载内核和文件系统的镜像

/oscomp_testcases

OS比赛用到的测例。目前是2021年版本的,仅作为参考

/repo

每周的进展交流

/doc

帮助文档,定位是讲解OS设计

/kernel/src

操作系统本体

main.rs

多核启动及初始化

loader.rs

加载用户程序

constants.rs

代码中用到的几乎所有常量

utils.rs

一些常用但跟 OS 设计关系不大的函数

timer.rs

时钟中断与相关寄存器

console.rs

no_std 下的 print!println! 封装

error.rs

操作系统自己定义的错误处理

lang.rs

panic时的处理,主要是panic_handler

/arch

程序入口以及对其他一些内嵌汇编的封装,包括 sbi 调用

/trap

中断与异常处理。目前内核与用户中断处理尚未分离

/task

任务管理及调度

/syscall

系统调用处理

/drivers

设备和驱动

/file

一些满足文件要求的类(标准输入输出/管道/文件系统中的文件等),以及每个进程管理文件描述符的 FdManager

/loaders

.elf 文件中读取用户程序信息并生成对应的VMA

目前所有用户程序在启动时被加载文件系统中。

/memory

页表虚拟地址空间管理

/memory/allocator

堆、页帧、进程号(PID)的分配,需要在启动时由且仅由一个核进行初始化

/memory/areas

表示一段有相同访问权限的内存区间,也负责处理区间内的缺页异常

/memory/page_table_impl_rv64_sv39

基于 crate riscv 实现的 riscv64 平台下SV39模式的页表。目前已废弃

目前使用的页表在 /memory/page_table.rs 中,是手写的SV39模式的页表。