0%

2024年开源操作系统训练营总结-winddevil/ArceOS第七节课笔记

概念

关键是在于这个虚拟化层,我们用虚拟化层来实现对硬件抽象层的虚拟化.

虚拟化的效率高是因为Hypervisor的体系结构环境是相同的.

这里的II型是KVM这种.1.5型可能更多的是

物理设备只有一个CPU的时候用多任务假装是vcpu.

有点像虚拟内存<->物理内存.用的也是页表的方式来建立对应关系.

vcpu的方式是一样的实现vDev.其实就是怎么把一个设备的划分成很多小的粒度,然后再分配资源给它.

最简Hypervisor执行流程:

  1. 加载Guest OS内核Image到新建地址空间。
  2. 准备虚拟机环境,设置特殊上下文。
  3. 结合特殊上下文和指令sret切换到V模式,即VM-ENTRY。
  4. OS内核只有一条指令,调用sbi-call的关机操作。
  5. 在虚拟机中,sbi-call超出V模式权限,导致VM-EXIT退出虚拟机,切换回Hypervisor。
  6. Hypervisor响应VM-EXIT的函数检查退出原因和参数,进行处理,由于是请求关机,清理虚拟机后,退出。

这里这个V模式一定要注意,之前我们只涉及了US模式.

S变成了HS.
HS是关键,作为联通真实世界和虚拟世界的通道.体系结构设计了双向变迁机制.
后边实现的很多东西都来自于HS这个特权级的寄存器.

H扩展后,S模式发送明显变化:原有s[xxx]寄存器组作用不变,新增hs[xxx]和vs[xxx]
hs[xxx]寄存器组的作用:面向Guest进行路径控制,例如异常/中断委托等
vs[xxx]寄存器组的作用:直接操纵Guest域中的VS,为其准备或设置状态

意思好像是要用HS里的H去假冒VS?

根据spv的不同决定sret会进入虚拟化还是进入user.

这里还多一个spvp,指示HS对V模式下地址空间是否有操作权限,1表示有权限操作,0无权限.

总结下来感觉虚拟机更像是一个进程,但是它又比进程多很多东西,需要运行自己的一套寄存器.

实验

运行之后是触发了一个IllegalInstructiontrap.

所以确实是会报错的.

这里要注意是QEMU的版本问题,如果是默认的6.x会导致无法正常进入vmexit_handler.
我这里安装的QEMU9.1.0版本,可以参见我自己的博客[rCore学习笔记 03]配置rCore开发环境 - winddevil - 博客园,下载的时候把版本改成9.1.0即可.

这里知道li指令访问了a7寄存器违反了不能访问csr的规定.

由于li的长度为4,我们做出如下修改tf.sepc += 4;:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// modules/axhal/src/arch/riscv/trap.rs
#[no_mangle]
fn riscv_trap_handler(tf: &mut TrapFrame, from_user: bool) {
let scause: scause::Scause = scause::read();
match scause.cause() {
#[cfg(feature = "uspace")]
Trap::Exception(E::UserEnvCall) => {
tf.regs.a0 = crate::trap::handle_syscall(tf, tf.regs.a7) as usize;
tf.sepc += 4;
}
Trap::Exception(E::LoadPageFault) => handle_page_fault(tf, MappingFlags::READ, from_user),
Trap::Exception(E::StorePageFault) => handle_page_fault(tf, MappingFlags::WRITE, from_user),
Trap::Exception(E::InstructionPageFault) => {
handle_page_fault(tf, MappingFlags::EXECUTE, from_user)
}
Trap::Exception(E::Breakpoint) => handle_breakpoint(&mut tf.sepc),
Trap::Interrupt(_) => {
handle_trap!(IRQ, scause.bits());
}
Trap::Exception(E::IllegalInstruction) => {
tf.sepc += 4;
info!("Illegal Instruction");
}
_ => {
panic!(
"Unhandled trap {:?} @ {:#x}:\n{:#x?}",
scause.cause(),
tf.sepc,
tf
);
}
}
}

课后作业

注意触发缺页异常之后要调整sepc的值,防止再回去再触发缺页异常然后无限循环了.

因为未知原因会卡住,这题的解题思路应该和h_1_0是一样的.