到达Host的abort都是由于缺乏Stage 2页表转换条目导致的,这个可能是Guest需要分配更多内存而必须为其分配内存页,或者也可能是Guest尝试去访问IO空间,IO操作由用户空间来模拟的。两者的区别是触发异常的IPA地址是否已经在用户空间中注册为标准的RAM;
调用流程来了:
kvm_vcpu_trap_get_fault_type用于获取ESR_EL2的数据异常和指令异常的fault status code,也就是ESR_EL2的ISS域;
kvm_vcpu_get_fault_ipa用于获取触发异常的IPA地址;
kvm_vcpu_trap_is_iabt用于获取异常类,也就是ESR_EL2的EC,并且判断是否为ESR_ELx_IABT_LOW,也就是指令异常类型;
kvm_vcpu_dabt_isextabt用于判断是否为同步外部异常,同步外部异常的情况下,如果支持RAS,Host能处理该异常,不需要将异常注入给Guest;
异常如果不是FSC_FAULT,FSC_PERM,FSC_ACCESS三种类型的话,直接返回错误;
gfn_to_memslot,gfn_to_hva_memslot_prot这两个函数,是根据IPA去获取到对应的memslot和HVA地址,这个地方就对应到了上文中第二章节中地址关系的建立了,由于建立了连接关系,便可以通过IPA去找到对应的HVA;
如果注册了RAM,能获取到正确的HVA,如果是IO内存访问,那么HVA将会被设置成KVM_HVA_ERR_BAD。kvm_is_error_hva或者(write_fault && !writable)代表两种错误:1)指令错误,向Guest注入指令异常;2)IO访问错误,IO访问又存在两种情况:2.1)Cache维护指令,则直接跳过该指令;2.2)正常的IO操作指令,调用io_mem_abort进行IO模拟操作;
handle_access_fault用于处理访问权限问题,如果内存页无法访问,则对其权限进行更新;
user_mem_abort,用于分配更多的内存,实际上就是完成Stage 2页表映射的建立,根据异常的IPA地址,已经对应的HVA,建立映射,细节的地方就不表了。
来龙去脉摸清楚了,那就草草收场吧,下回见了。
参考《Arm Architecture Registers Armv8, for Armv8-A architecture profile》
欢迎关注个人公众号,不定期分享技术文章。