- 虚拟机内存角度分析中列出了访存流程
想象中是这样子的流程
1. guest 内存相关 的初始化 (HTTBR 与 VTTBR 的设置) // 参考 "host 中的 HTTBR" 和 "host 中的 VTTBR"
2. guest os 开始运行
3. guest os 读 A 地址
4. 陷入 host PL2 异常 // host os 开始运行
4.1 异常退出
4.2 做相应的动作
4.3 注入中断
4.4 guest enter // guest os 开始 运行
5. guest os 陷入 guest PL1 异常
6. guest PL1 异常处理
6.1 保存现场
6.2 做相应的动作
6.2 恢复现场,恢复 pc 为访存时的pc
7. guest os 读 A 地址 // 和 3 是同一个动作
8. guest os 获取 A 地址的值
注意 : 4.2 和 6.2 是 我们关注的重点
————————————————
版权声明:本文为CSDN博主「__pop_」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/u011011827/article/details/120864037
流程中 需要关注两点
1.
4.2 host PL2 中的异常处理
可参考 https://blog.csdn.net/u011011827/article/details/120986330 中的 kvm_handle_guest_abort
2.
6.2 : guest PL1 中的 异常处理
可参考 https://blog.csdn.net/u011011827/article/details/117430300 中的 "linux-5.11 对 data abort 异常的处理"
host PL2 中的异常处理 kvm_handle_guest_abort
两种情况会进入
1. guest OS 申请内存
2. guest OS 访问由用户空间模拟的 I/O内存
会按照以下过程区分
1. 确认 导致 IPA 的 fault
2. 确认 内存区域是否已按用户空间注册为标准RAM
kvm_handle_guest_abort 主要有三个程序流
io_mem_abort // 对应 guest OS 访问由用户空间模拟的 I/O内存 ,IPA非标准RAM
handle_access_fault // 对应 guest OS 访问内存 的权限错误 ,IPA是标准RAM
user_mem_abort // 对应 guest OS 申请内存 ,IPA是标准RAM
第一次 KVM_RUN
guest enter
guest exit
handle_exit
kvm_handle_guest_abort
fault_ipa = kvm_vcpu_get_fault_ipa(vcpu);
gfn = fault_ipa >> PAGE_SHIFT; // 0x100
memslot = gfn_to_memslot(vcpu->kvm, gfn);
hva = gfn_to_hva_memslot_prot(memslot, gfn, &writable); // 0xb6f35000
user_mem_abort
guest enter
guest exit
handle_exit
kvm_handle_guest_abort
fault_ipa = kvm_vcpu_get_fault_ipa(vcpu);
gfn = fault_ipa >> PAGE_SHIFT; // 0x8
memslot = gfn_to_memslot(vcpu->kvm, gfn);
hva = gfn_to_hva_memslot_prot(memslot, gfn, &writable); // 0xc0000000
io_mem_abort
vcpu_data_guest_to_host
kvm_mmio_write_buf
kvm_io_bus_write
run->mmio.is_write = is_write; // 1
run->mmio.phys_addr = fault_ipa; // 0x8000
vcpu->mmio_needed = 1;
memcpy(run->mmio.data, data_buf, len); // H
run->exit_reason = KVM_EXIT_MMIO;
little-qemu 打印H
第二次 KVM_RUN
guest enter
guest exit
handle_exit
kvm_handle_guest_abort
fault_ipa = kvm_vcpu_get_fault_ipa(vcpu);
gfn = fault_ipa >> PAGE_SHIFT;
memslot = gfn_to_memslot(vcpu->kvm, gfn);
hva = gfn_to_hva_memslot_prot(memslot, gfn, &writable);
io_mem_abort
vcpu_data_guest_to_host
kvm_mmio_write_buf
kvm_io_bus_write
run->mmio.is_write = is_write; // 1
run->mmio.phys_addr = fault_ipa; // 0x8000
vcpu->mmio_needed = 1;
memcpy(run->mmio.data, data_buf, len); // e
run->exit_reason = KVM_EXIT_MMIO;
little-qemu 打印e
第N次 KVM_RUN
guest enter
guest exit
handle_exit
kvm_handle_guest_abort
fault_ipa = kvm_vcpu_get_fault_ipa(vcpu);
gfn = fault_ipa >> PAGE_SHIFT;
memslot = gfn_to_memslot(vcpu->kvm, gfn);
hva = gfn_to_hva_memslot_prot(memslot, gfn, &writable);
io_mem_abort
vcpu_data_guest_to_host
kvm_mmio_write_buf
kvm_io_bus_write
run->mmio.is_write = is_write; // 1
run->mmio.phys_addr = fault_ipa; // 0x8000
vcpu->mmio_needed = 1;
memcpy(run->mmio.data, data_buf, len); // '\n'
run->exit_reason = KVM_EXIT_MMIO;
little-qemu 打印'\n'
第N+1次 KVM_RUN
guest enter
guest exit
handle_exit
kvm_handle_guest_abort
fault_ipa = kvm_vcpu_get_fault_ipa(vcpu);
gfn = fault_ipa >> PAGE_SHIFT;
memslot = gfn_to_memslot(vcpu->kvm, gfn);
hva = gfn_to_hva_memslot_prot(memslot, gfn, &writable);
io_mem_abort
vcpu_data_guest_to_host
kvm_mmio_write_buf
kvm_io_bus_write
run->mmio.is_write = is_write; // 1
run->mmio.phys_addr = fault_ipa; // 0x10000
vcpu->mmio_needed = 1;
memcpy(run->mmio.data, data_buf, len); // 0
run->exit_reason = KVM_EXIT_MMIO;
little-qemu 打印 "Guest Exit!"