整体架构和启动过程
.
├── README.md
├── status.md 支持状态文档
├── docs 各种文档,包含课程报告等
├── kernel 内核主项目目录
├── user 用户程序开发环境
├── crate 从内核中独立出去的库,包含内存管理、进程管理等
└── riscv-pk BBL for RV32
.
├── src 代码目录
│ ├── arch 平台相关部分代码
│ │ ├── riscv32
│ │ └── x86_64
│ ├── xxx.rs 平台无关部分代码
│ └── ...
├── target 生成文件目录
├── Cargo.lock cargo依赖锁定文件
├── Cargo.toml cargo项目配置文件
├── build.rs cargo build 前会执行的build脚本
├── Makefile
├── riscv32-blog_os.json riscv32的target配置文件
└── x86_64-blog_os.json x86_64的target配置文件
.
├── bbl bbl接口库
├── bit-allocator 线段树实现的0-N整数分配器,用来快速分配物理页
├── memory 内存管理模块
├── process 进程管理模块
├── riscv riscv底层支持模块(Fork: rust-embedded/riscv)
└── sync 基于std的同步互斥测试程序
.
├── Cargo.lock
├── Cargo.toml
├── Makefile
├── riscv32-ucore.json 用于用户程序的target配置文件
├── x86_64-ucore.json ……
├── src
│ └── bin
│ └── hello.rs 用户程序
├── ucore-ulib RustOS的用户程序库
# 以上用于编写Rust用户程序
# 以下是现有二进制用户程序打包的磁盘镜像,未来可能被替代
├── ucore32.img ucore x86-32用户程序 SFS磁盘镜像
├── user-riscv.img ucore rv32用户程序 SFS磁盘镜像
└── xv6_64.img xv6-x86_64用户程序 ……
整体上和原版ucore一致,只是实现细节有所不同。
首先由Bootloader为Kernel配置好运行环境,设置好栈寄存器,跳转到Rust代码。
- riscv32:
arch/riscv32/mod.rs::rust_main()
- x86_64:
arch/x86_64/mod.rs::_start()
以x86_64为例,上面的函数依次执行以下初始化工作:
- 1.Log模块初始化:设置全局Logger,此后即可使用
debug!
等宏输出不同等级的调试信息,它们会在终端中以彩色显示。 - 2.中断初始化:设置中断向量表,此后中断处理函数即可工作。
- 3.内存初始化:根据bootloader传来的内存信息……
- 1.初始化物理帧分配器,此后页表即可工作
- 2.为内核构造新的页表并启用(已废弃,转移到bootloader)
- 3.初始化堆分配器:此后即可在堆上分配内存,并使用core中如Vec、BTreeSet等强力工具。
- 4.GDT和TSS初始化:后面用户程序要用到
- 5.设备初始化:PIC/APIC,时钟,串口,键盘
RISCV下则相对简单:
- 1.Log模块初始化
- 2.中断初始化
- 3.内存初始化:……
- 4.时钟初始化
执行完毕后,跳转到kmain函数。
初始化线程管理器,并添加当前线程和idle线程。
它作为一个内核线程运行。首先加载用户程序磁盘数据,x86_64下通过IDE磁盘读取 ,riscv32下将磁盘文件硬连接到kernel中,通过内存读取。然后使用SFS库解析磁盘内容,根据用户输入的程序名,将相应用户程序数据读取到内存。使用ELF库解析用户程序内容,设置好页表映射,创建新的线程。
Kernel Shell在为用户程序创建好新的线程后,会主动wait它,触发调度,切换到此线程执行。根据其初始内核栈帧的设置,上下文切换后它将进入用户态执行。
当用户程序运行一段时间后,可能由于系统调用、时钟中断、发生异常等原因,进入中断处理函数,并发生线程切换。
当用户程序主动或被动地退出后,它所占用的资源会被回收,Kernel Shell被唤醒,上述过程循环往复。
Last modified 4yr ago