对于无VHE的情况
1. kvm_get_hyp_vector会给出__kvm_hyp_vector(A12/17/15似乎有不同的处理)
2. kvm_arch_hardware_enable->_kvm_arch_hardware_enable->cpu_hyp_reinit->cpu_init_hyp_mode->
__cpu_init_hyp_mode->kvm_call_hyp(pgd, stack, vector)
需要单独拿出kvm_call_hyp来说一下:
在物理CPU没有将__kvm_hyp_vector配入vbar_el2之前,物理CPU中并非没有异常向量,
__hyp_stub_vectors会在物理CPU启动阶段就被配入bar_el2,此异常向量组仅有一条异常向量有效,
也就是响应HVC异常的el1_sync有效,而el1_sync的逻辑只能做新异常向量的配入(以及一些无用操作)。
而virt/kvm/arm/arm.c(4.15 kernel目录,后来这个文件移到了arch/arm64/...)中
的cpu_init_hyp_mode(你没看错,就是2.开头的调用栈里的那个函数)会执行
__hyp_set_vectors(kvm_get_idmap_vector()),将__kvm_hyp_init异常向量组配入vbar,
这个异常向量组就厉害了,此异常向量组仅有一条异常向量有效,
也就是响应HVC异常的__do_hyp_init有效。
上面这句话有没有点眼熟,似乎el1_sync也是这个功效?还是有一些差别的,
__do_hyp_init能接收3各参数,pgd(EL2页表基地址),stack(EL2栈帧基址),vector(EL2异常向量)
__kvm_hyp_init异常向量组是一个临时的异常向量组,但是它能够完成最终EL2异常向量的配置,
小节2. 开头的调用栈中kvm_call_hyp(pgd, stack, vector)即利用其中的__do_hyp_init,
完成__kvm_hyp_vector的最终配入。
这其中有一个点就是kvm_call_hyp()在__kvm_hyp_init异常向量组生效时,
需要传入pgd, stack, vector,由__do_hyp_init处理,
而之后__kvm_hyp_vector向量组生效后,就是根据要执行的操作来传入参数并由各向量处理了
(如el1_sync(与__hyp_stub_vectors中el1_sync不同喔~)/el1_irq等)
我有试图猜测需要__do_hyp_init作为媒介完成__kvm_hyp_vector的配入而不是直接使用
__hyp_stub_vectors的原因,但是并没有啥精彩的想法,所以事实是这样,就这样吧。
3. 如果你觉着自己并没有耐心搞清楚小节2. 我也可以用一句话将关键点说清楚:
KVM利用内核启动默认__hyp_stub_vectors异常向量组中的HVC异常向量el1_sync,
将异常向量组替换为__kvm_hyp_init,
然后又利用__kvm_hyp_init异常向量组中的HVC异常向量__do_hyp_init,
将异常向量组__kvm_hyp_vector最终配入。
对于有VHE的情况,无VHE情况下的操作都不需要;
我这样解释这个问题:linux内核都已经在EL2了,EL2还需要额外的异常向量组做什么呢,无处安放呀。
__kvm_hyp_vector如何成为最终的EL2异常向量表
最新推荐文章于 2024-07-07 03:17:43 发布