整体架构和启动过程
项目文件夹
root
kernel
crate
user
启动过程概览
整体上和原版ucore一致,只是实现细节有所不同。
Boot
首先由Bootloader为Kernel配置好运行环境,设置好栈寄存器,跳转到Rust代码。
riscv32:
arch/riscv32/mod.rs::rust_main()
x86_64:
arch/x86_64/mod.rs::_start()
平台初始化
以x86_64为例,上面的函数依次执行以下初始化工作:
Log模块初始化:设置全局Logger,此后即可使用
debug!
等宏输出不同等级的调试信息,它们会在终端中以彩色显示。中断初始化:设置中断向量表,此后中断处理函数即可工作。
内存初始化:根据bootloader传来的内存信息……
初始化物理帧分配器,此后页表即可工作
为内核构造新的页表并启用(已废弃,转移到bootloader)
初始化堆分配器:此后即可在堆上分配内存,并使用core中如Vec、BTreeSet等强力工具。
GDT和TSS初始化:后面用户程序要用到
设备初始化:PIC/APIC,时钟,串口,键盘
RISCV下则相对简单:
Log模块初始化
中断初始化
内存初始化:……
时钟初始化
执行完毕后,跳转到kmain函数。
线程初始化
初始化线程管理器,并添加当前线程和idle线程。
进入Kernel Shell
它作为一个内核线程运行。首先加载用户程序磁盘数据,x86_64下通过IDE磁盘读取,riscv32下将磁盘文件硬连接到kernel中,通过内存读取。然后使用SFS库解析磁盘内容,根据用户输入的程序名,将相应用户程序数据读取到内存。使用ELF库解析用户程序内容,设置好页表映射,创建新的线程。
执行线程切换
Kernel Shell在为用户程序创建好新的线程后,会主动wait它,触发调度,切换到此线程执行。根据其初始内核栈帧的设置,上下文切换后它将进入用户态执行。
当用户程序运行一段时间后,可能由于系统调用、时钟中断、发生异常等原因,进入中断处理函数,并发生线程切换。
当用户程序主动或被动地退出后,它所占用的资源会被回收,Kernel Shell被唤醒,上述过程循环往复。
Last updated