little-qemu&guest 中的 虚拟机中断角度 之 访存异常实例

想象中是这样子的流程
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.26.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!"

おすすめ

転載: blog.csdn.net/u011011827/article/details/121011815