diff --git "a/source/_posts/2024-\347\247\213\345\206\254\345\255\243\345\274\200\346\272\220\346\223\215\344\275\234\347\263\273\347\273\237\350\256\255\347\273\203\350\220\245\347\254\254\344\270\211\351\230\266\346\256\265\346\200\273\347\273\223-yck.md" "b/source/_posts/2024-\347\247\213\345\206\254\345\255\243\345\274\200\346\272\220\346\223\215\344\275\234\347\263\273\347\273\237\350\256\255\347\273\203\350\220\245\347\254\254\344\270\211\351\230\266\346\256\265\346\200\273\347\273\223-yck.md" new file mode 100644 index 0000000000..6105617511 --- /dev/null +++ "b/source/_posts/2024-\347\247\213\345\206\254\345\255\243\345\274\200\346\272\220\346\223\215\344\275\234\347\263\273\347\273\237\350\256\255\347\273\203\350\220\245\347\254\254\344\270\211\351\230\266\346\256\265\346\200\273\347\273\223-yck.md" @@ -0,0 +1,205 @@ +--- +title: 2024-秋冬季开源操作系统训练营第三阶段总结-yck +date: 2024-12-02 02:00:28 +tags: + - author: AoligeiY +--- + +# Areos引导机制 + +- 首先进入`axhal`中平台架构的boot程序的`_start`函数,参数为OpenSBI传入的两个参数,一个是`hartid`用于识别CPU,一个是`dtb_ptr`传入DTB的指针。 +- 然后会建立栈用于函数调用,准备页表启动MMU分页机制,后即可进入Rust。 + +然后进入axruntime初始化应用运行时的环境,即根据feature条件编译各组件框架 + + + +# 启用页表机制 + +SBI配置FW_TEXT_START,BIOS负责把SBI加载到内存的起始位置 + +0x8000 0000存放SBI,SBI会跳转到以0x8020 0000起始的内核代码,存放.bss、.data、.rodata、.text段。 + +axhal中的linker_riscv64-qemu-virt.lds指导rust的链接器来实现段布局 + + +一阶段:即上面提到`_start`函数中的初始化MMU,将物理地址空间**恒等映射**,再添偏移量。 + +二阶段:重建映射,一阶段的映射并**没有添加权限**进行管理。若启用"paging"的feature,首先会调用axmm中的`init_memory_management()`,进行创建内核空间(`new_kernel_aspace()`),将根页表地址写入stap寄存器(`axhal::paging::set_kernel_page_table_root`)。 + + +# 多任务 + +启用"multitask"的feature,执行`axtask::init_scheduler()`,会进行就绪队列的初始化,以及系统timers的初始化。 + +- 就绪队列的初始化:初始化系统任务idle、main、gc + - main为主任务,其他任务均为其子任务 + - idle,其他任务都阻塞时会执行它 + - gc,除main之外的任务退出后,将由gc负责回收清理 + + + +## 调度算法 + +### CFS + +"init_vruntime"在os启动调度的时候决定调度顺序,"nice"则是优先级,优先级越大"vruntime"增长越慢,从而达到高优先。 + +当时间片结束后,当前任务将被为设为可抢占,当前任务释放控制权,加入就绪队列。并且如果外部条件满足抢占,则会将就绪队列中的队首弹出并切换到该任务 + + +# 宏内核 + +### m_1_0启动 + +- 首先为应用创建独立的用户地址空间。 + +`axmm::new_user_aspace` + +- 将应用程序代码加载到地址空间。 + +`load_user_app` + +- 初始化用户栈 + +`init_user_stack` + +- spawn创建用户任务,以用户地址空间及应用入口、用户栈为参数 + +`task::spawn_user_task` + +- 当前任务释放CPU,使用户任务运行 + +`user_task.join` + + + +### 用户空间 + + +页表管理内核地址空间和用户地址空间 + +内核地址空间只有高端(高地址)存放内核代码数据 + +用户地址空间高端存放内核,但这部分的页表项设为用户不可见,只有陷入内核态之后才能访问。低端地址存放应用 + +每个用户地址空间高端的内核均相同,只有存放应用的区域不同 + + + + +地址空间后端Backend: + +Linear:目标物理地址空间已经存在,直接建立映射关系,物理页帧必须连续 + +Alloc:仅建立空映射,当真正被访问时将会触发缺页异常,然后在缺页响应函数内部完成物理页帧的申请和补齐映射,也就是Lazy方式。物理页帧通常情况下不连续 + + + +### ELF格式应用加载 + + +代码段加载无偏移。 + +数据段加载到虚拟地址空间分为.data、.bss。但.bss在ELF文件中为节省空间紧凑存储不做存放,仅做标记位置和长度。内核直接预留空间并清零 + + + +### 缺页异常 + +当发生缺页异常时,由aspace的`handle_page_fault`来完成对物理页帧的申请与映射 + +首先检查发生页面错误的虚拟地址 `vaddr` 是否在当前虚拟地址范围 `va_range` 内。 + +然后找到`vaddr`的区域area,进入area的后端,缺页异常通常由后端Alloc的Lazy策略造成,故进入Alloc分支调用`handle_page_fault_alloc`对页表`remap`完成页表映射 + + + +# Hypervisor + +虚拟化基于RISCV64的S特权级的H扩展,Host将在HS特权级下进行`VM_ENTRY`以及`VM_EXIT` + + + +S特权模式进行H扩展后,原有的s[xxx]寄存器组作用不变,将新增hs[xxx]和vs[xxx] + +- hs[xxx]寄存器组的作用:面向Guest进行路径控制 +- vs[xxx]寄存器组的作用:直接操纵Guset域中的VS,为其准备或设置状态 + + + +设置hstatus的SPV位(指示特权级模式的来源,1为VS,0为U)SPVP位(指示HS对V模式下地址空间是否由操作权限) + + + +启动Guest之前,设置Guest的sstatus,设置初始特权级为Supervisor + +设置sepc为OS启动入口地址VM_ENTRY,地址为0x8020 0000 + + + +run_guest切换:保存Host上下文,将Guest上下文(第一次切换为伪造的上下文)载入寄存器组 + + + +VM_EXIT返回Host:保存Guest上下文,将Host上下文载入寄存器组 + + + +### Guest和Host地址空间 + +Hypervisor负责基于Host物理地址空间HPA面向Guest映射Guest物理地址空间GPA + +Guest会认为GPA是实际的物理地址空间,它基于satp映射内部的GVA虚拟空间 + + +启用RISC64指令集的G扩展: + +- 引入vsatp用于第一阶段的页表翻译,即将Guest的虚拟地址空间映射为Guest的物理地址空间 +- 引入hgatp用于第二阶段的页表翻译,即将Guest的物理地址空间映射到Host的物理地址空间 + + + +### 虚拟机物理地址空间布局 + + +低端区域留给设备空间和DMA + +0x8000 0000在Host中是存放SBI的,但是虚拟机没有M模式,是无法访问SBI,所以这部分进行保留 + +0x8020 0000存放内核 + +高于内核的地址用作物理内存区 + + + +### Hypervisor主逻辑 + +- 准备VM的资源:VM地址空间和单个vCPU +- 切换到进入Guest的代码 +- 响应VM_EXIT各种原因的代码 + + +实现流程: + +1. 创建地址空间 为目标虚拟机创建物理地址空间 axmm +2. 建立区域布局 在地址空间中为Guest内核和设备建立区域 axmm +3. 加载内核 把Guest内核Image加载到内核区域 axmm, axfs +4. 初始化vCPU 把vCPU的启动入口设置为Guest内核入口,同时设置EPT页表地址 + +最后在Host和Guest环境循环切换,支持虚拟机持续运行 + + + +VCPU的准备: + +- 通过`set_entry(VM_ENTRY)`设置sepc来配置入口地址0x8020 0000 +- 通过`set_ept_root`向hgatp设置模式(SV39)和根页表的页帧 + + + + +### axruntime和axhal时钟中断处理 + +`axhal::irq::register_handler` 通过`update_timer`在中断向量表中注册对应的中断响应函数,更新时钟。然后`axtask::on_timer_tick()`触发定时任务 +