项目架构与内核架构设计
项目总体架构
为了进行混合内核与宏内核的对比,本项目实现了混合内核与宏内核两种内核架构,项目总体结构如下图所示:
项目总体采用层次化软件开发方法,自底向上分为驱动、硬件抽象层、内核对象层、系统调用层、装载器和上层标准库和应用程序。
硬件抽象层(Hardware Abstraction Layer,HAL)定义一套硬件操作 API,提供给上层的内核对象使用,HAL层内部的实现和依赖的环境,对于上层内核对象 来说是完全透明的,且上层内核对象只能通过 HAL 层的 API 来操作硬件。HAL 层只给出接口定义,具体的实现可以有多种硬件架构,如 x86_64、aarch64 等(目前只实现了x86_64架构),在编译时通过 Rust 语言的 feature 条件编译选项将 HAL 定义的硬件接口绑定到具体的硬件平台实现上去。这种做法一方面可以将底 层的 unsafe 代码进行独立封装与集中检查测试,限制上层对象只能通过 HAL 层的 API 操作硬件,从而最大限度地利用 Rust 语言提供的内存安全特性,另一方面屏 蔽了不同硬件架构的硬件细节,使上层内核对象的操作独立于硬件。
内核对象层(Kernel Objects)基于 HAL 层给出的硬件接口,实现内核数据结 构和他们的方法(如进程线程等)。由于混合内核与宏内核的内部实现有所不同,分别实现宏内核对象和混合内核对象两套对象。
系统调用层(Syscall Layer)根据内核对象的方法实现系统调用接口。为了直接支持musl-libc,我们直接实现了Linux系统调用。
加载器(Loader)位于系统调用层之上,其向下使用系统调用层给出的系统调用 API,完成内核对象初始化、系统调用入口设定、第一个用户程序加载和启动的工作。用户程序(App)层运行用户态应用程序,可以直接使用内核提供的系统调用,也可以运行在系统调用层之上的 c 标准库(musl-libc)上。
代码目录树
项目的代码目录树如下
.
├── boot // 启动内核
├── crates // 有修改的第三方库
├── executor // 协程执行器
├── hal // 硬件抽象层
├── hybrid-objects // 混合内核对象
├── hybrid-syscalls // 混合内核系统调用
├── loader // 加载器
├── misc // 杂项
├── monolithic-objects // 宏内核对象
├── monolithic-syscalls // 宏内核系统调用
├── musl // musl源码
├── Ncore // 顶层内核
├── rcore-fs-use // 构建文件系统
├── tutorial // 文档
├── user-c // C语言用户程序
├── user-components // 用户态组件
├── user-rs // Rust用户程序
└── Question.md // 本题目简介
其中的boot、executor、hal、hybrid-objects、hybrid-syscalls、loader、monolithic-objects、monolithic-syscalls、Ncore、user-rs都被实现为单独的Rust crate。